Calculate the great circle distance between two latitudes and longitudes in C#

[great circle distance]

At a small scale, the world is relatively flat. At larger scale, however, is it roughly spherical. (Sorry flat-earthers.) That means the shortest distance between two points on the globe is not a straight line. (Unless you have amazing teleportation or tunneling technology.) In that case, the shortest path between two points is a great circle distance. A great circle is a circle defined by a plane that passes through the two points and the center of the Earth.

This example uses the haversine formula to calculate the great circle distance between two points defined by their latitudes and longitudes. You can find a description of the formula in the Wikipedia article Haversine formula.

The heart of the example is the following method, which calculates the great circle distance.

// Calculate the great circle distance between two points.
private double GreatCircleDistance(
    double lat1, double lon1, double lat2, double lon2)
{
    const double radius = 6371; // Radius of the Earth in km.
    lat1 = DegreesToRadians(lat1);
    lon1 = DegreesToRadians(lon1);
    lat2 = DegreesToRadians(lat2);
    lon2 = DegreesToRadians(lon2);
    double d_lat = lat2 - lat1;
    double d_lon = lon2 - lon1;
    double h = Math.Sin(d_lat / 2) * Math.Sin(d_lat / 2) +
        Math.Cos(lat1) * Math.Cos(lat2) *
        Math.Sin(d_lon / 2) * Math.Sin(d_lon / 2);
    return 2 * radius * Math.Asin(Math.Sqrt(h));
}

The method sets the constant radius equal to the approximate radius of the Earth in kilometers. If you want the result to be in some other unit such as meters or miles, you can change this constant or you can convert the method’s result from kilometers into the new units.

The method then converts the input latitudes and longitudes from degrees to radians. It then calculates the result of the haversine formula and returns the result.

The example uses two interesting helper methods. The first is the following DegreesToRadians method.

// Convert the degrees into radians.
private double DegreesToRadians(double degrees)
{
    return degrees * Math.PI / 180.0;
}

This method converts an angle in degrees into radians by multiplying it by π and then dividing it by 180.

The second helper method parses a latitude or longitude that is stored in a string. It expects the string to include a measure of degrees, possibly followed by the ° symbol. It can then include the measurement’s minutes and seconds, followed either by spaces or by ‘ or “. The whole thing should then be followed by N, S, E, or W. For example, the method accepts the following formats.

  • 1° 14′ N
  • 1 14′ 0″ N
  • 1° 14 0N
  • 1 14 0 N

The following code shows the method.

private const string Deg = "°";

// Parse a latitude or longitude.
private double ParseLatLon(string str)
{
    str = str.ToUpper().Replace(Deg, " ").Replace("'", " ").Replace("\"", " ");
    str = str.Replace("S", " S").Replace("N", " N");
    str = str.Replace("E", " E").Replace("W", " W");
    char[] separators = {' '};
    string[] fields = str.Split(separators,
        StringSplitOptions.RemoveEmptyEntries);

    double result =             // Degrees.
        double.Parse(fields[0]);
    if (fields.Length > 2)      // Minutes.
        result += double.Parse(fields[1]) / 60;
    if (fields.Length > 3)      // Seconds.
        result += double.Parse(fields[2]) / 3600;
    if (str.Contains('S') || str.Contains('W')) result *= -1;
    return result;
}

This method first capitalizes the string and removes any ° characters. It then replaces the ‘ and ” characters with spaces. It also adds a space in front of any N, S, E, or W characters.

Next, the code splits the value into fields delimited by space characters. It assumes that the first field is the measurement’s degrees and parses it. Then, if the value contains more than two fields, it parses the second field and divides the result by 60 to include the value’s minutes. If the value includes more than three fields, the code parses the third field and uses it for the value’s seconds.

Finally, if the value ends with S or W, it negates the result.

Note that this method isn’t all that robust. For example, it doesn’t use the ‘ and ” characters to determine which fields represent minutes and seconds. Feel free to make an improved version that does a better job of understanding the possible formats. (You might want to use regular expressions.)

Download the example program to see additional details such as how the program builds a list of sample cities that you can select from their combo boxes.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in mathematics | Tagged , , , , , , , , , | Leave a comment

Load Excel records into a DataGridView in C#


[load Excel records]

This example shows how you can load Excel records into a DataGridView control. You can use similar techniques to load Excel data into other controls such as other kinds of grid controls or a TreeView control.

This example uses the Microsoft Excel interop library to build an Excel server. before you can use the library, you need to add a reference to it. To do that, open the Properties window, right-click References, and select Add Reference. On the COM tab, double-click the Microsoft Excel 14.0 Object Library entry.

To make using the library easier, add the following using directive to the top of the code file.

using Excel = Microsoft.Office.Interop.Excel;

To make it easier to find the Excel workbook, I added it to the project. To do that, open the Project menu and select Add Existing Item. Select the file and click Add.

Then in Solution Explorer, click on the workbook. in the Properties window, set its “Build Action” property to Content and set its “Copy to Output Directory” property to “Copy if newer.” Now when you run the program, the file will be copied into the executable directory so the program can find it easily.

When the program starts, the following code places the file’s location in the program’s text box.

// Initialize the File TextBox.
private void Form1_Load(object sender, EventArgs e)
{
    txtFile.Text = Application.StartupPath + "\\Books.xlsx";
}

When you click the Load button, the following code executes.

private void btnLoad_Click(object sender, EventArgs e)
{
    // Get the Excel application object.
    Excel.Application excel_app = new Excel.ApplicationClass();

    // Make Excel visible (optional).
    excel_app.Visible = true;

    // Open the workbook read-only.
    Excel.Workbook workbook = excel_app.Workbooks.Open(
        txtFile.Text,
        Type.Missing, true, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing);

    // Get the first worksheet.
    Excel.Worksheet sheet = (Excel.Worksheet)workbook.Sheets[1];

    // Get the used range.
    Excel.Range used_range = sheet.UsedRange;

    // Get the maximum row and column number.
    int max_row = used_range.Rows.Count;
    int max_col = used_range.Columns.Count;

    // Get the sheet's values.
    object[,] values = (object[,])used_range.Value2;

    // Get the column titles.
    SetGridColumns(dgvBooks, values, max_col);

    // Get the data.
    SetGridContents(dgvBooks, values, max_row, max_col);

    // Close the workbook without saving changes.
    workbook.Close(false, Type.Missing, Type.Missing);

    // Close the Excel server.
    excel_app.Quit();
}

This code creates an Excel application object and uses it to open the workbook. Notice that the Workbooks.Open method (and many other Excel application methods) take parameters that are non-specific objects. Even though it is common to use only a few of those parameters, you cannot simply set the others to null. Instead you should use the special value Type.Missing to indicate that you are not using a parameter.

The code then gets a references to the workbook’s first worksheet. If the data that you want is on one of the workbook’s other worksheets, select that one instead.

Next, the program needs to find out where the data is on the worksheet. It uses the sheet’s UsedRange property to get a Range that represents the cells that are used by the worksheet. Note that the range does not include completely empty rows and columns. This example’s workbook contains data in columns B through E and rows 3 through 12. The used range does not include the blank column A or the blank rows 1 and 2. That means the program will not waste space displaying empty rows and columns in the DataGridView.

Having found the used range, the code gets its number of rows and columns.

Next, the program uses the used range’s Value2 method to copy the values in the range into a two-dimensional array. It calls the helper methods SetGridColumns and SetGridContents to define the grid’s columns and to load Excel records into the grid.

After it has loaded the data, the program closes the workbook and the Excel server.

The following code shows the SetGridColumns helper method.

// Set the grid's column names from row 1.
private void SetGridColumns(DataGridView dgv,
    object[,] values, int max_col)
{
    dgvBooks.Columns.Clear();

    // Get the title values.
    for (int col = 1; col <= max_col; col++)
    {
        string title = (string)values[1, col];
        dgv.Columns.Add("col_" + title, title);
    }
}

This method loops through the cells in the data array’s first row and adds each value to the DatagridView control’s Columns collection. It sets a column’s name to the cell’s text with “col_” prepended in front of it. It sets the column’s text to the cell’s value.

The following code shows the SetGridContents helper method.

// Set the grid's contents.
private void SetGridContents(DataGridView dgv,
    object[,] values, int max_row, int max_col)
{
    // Copy the values into the grid.
    for (int row = 2; row <= max_row; row++)
    {
        object[] row_values = new object[max_col];
        for (int col = 1; col <= max_col; col++)
            row_values[col - 1] = values[row, col];
        dgv.Rows.Add(row_values);
    }
}

This method loops through the value array’s rows. It skips the first row because it contains the column headings. For each row, the code creates a row_values array to hold the values for the row. It then loops through that row’s columns and copies the corresponding values from the data array into the row_values array. After it has filled in the row_values array, the code adds the values to the DataGridView control’s row data.

That’s all there is to it. Download the example to see the program in action.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls, database, Excel, interoperability | Tagged , , , , , , , , , , , , | 2 Comments

Make a picture with a transparent hole in it in C#

[transparent hole]

The example Create oval images in C# shows how to make a transparent image with an oval-shaped picture in it. This example shows how to do the converse: it makes an image with a transparent hole in the middle of it.

There are several approaches that you might take. You might like to simply draw an ellipse filled with the color Color.Transparent on top of a picture. Unfortunately, when you use the color Color.Transparent, that tells the drawing system to not do anything. If you fill an ellipse with that color, then it simply isn’t drawn.

A second approach would be to use the Bitmap class’s MakeTransparent method to convert some other color into Color.Transparent. For example, you could fill an ellipse in the middle of the form with the color that has RGB components (0, 0, 1), which is practically black, and then use MakeTransparent to convert those pixels into Color.Transparent. Unfortunately, you would need to be sure that the image didn’t already contain any pixels with the color (0, 0, 1). If it did, then those pixels would come out transparent, too. You can work around that problem by first examining the original image’s pixels and converting any such pixels to black, which would be indistinguishable.

The approach that this post takes for making a transparent hole is to make a region representing all of the parts of the image except the hole. It then uses the region to fill a bitmap with the image, cropped to only act on the region.

The example Create oval images in C# explains the basic user interface: how the program handles mouse events and so forth. See that example for those details.

The big difference between that example and this one is the CutOutOval method that makes the image with the transparent hole. The following code shows that method.

private Bitmap CutOutOval(Point start_point, Point end_point)
{
    // Make a region covering the whole picture.
    Rectangle full_rect = new Rectangle(
        0, 0, OriginalImage.Width, OriginalImage.Height);
    Region region = new Region(full_rect);

    // Remove the ellipse from the region.
    Rectangle ellipse_rect =
        SelectedRect(start_point, end_point);
    GraphicsPath path = new GraphicsPath();
    path.AddEllipse(ellipse_rect);
    region.Exclude(path);

    // Draw.
    Bitmap bm = new Bitmap(OriginalImage);
    using (Graphics gr = Graphics.FromImage(bm))
    {
        gr.Clear(Color.Transparent);

        // Fill the region.
        gr.SetClip(region, CombineMode.Replace);
        gr.SmoothingMode = SmoothingMode.AntiAlias;
        using (TextureBrush brush =
            new TextureBrush(OriginalImage, full_rect))
        {
            gr.FillRectangle(brush, full_rect);
        }
    }
    return bm;
}

The code first makes a Rectangle that covers the image’s entire area. It uses the Rectangle to make a new Region object.

Next, the code creates a second Rectangle to represent the area where the transparent hole should go. It creates a GraphicsPath object and adds the ellipse to it. The code then uses the Region object’s Exclude method to exclude the ellipse from the Region.

At this point, the method starts drawing. It creates a new Bitmap that is a copy of the original image, and then makes an associated Graphics object. It clears the new Bitmap with the color Color.Transparent.

The code then calls the Graphics object’s SetClip method to set its clipping rectangle to the region. After this point, the Graphics object will only modify pixels that lie within the region.

The rest is relatively straightforward. The program uses the original image to make a brush and then uses the brush to fill the entire Bitmap. The elliptical area that was excluded from the region is not drawn, resulting in a transparent hole.

After it creates the image, the program draws a checkerboard and draws the image on top of it to show the transparent hole.

Download the example to see additional details.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in drawing, graphics, image processing | Tagged , , , , , , , , , | Leave a comment

Let the user zoom on a picture and draw in C#

[zoom]

The example Let the user zoom on a picture in C# allows the user to zoom in on a picture and draw on it. Unfortunately, it doesn’t handle the drawing properly when the image is scaled. It doesn’t scale the mouse’s position properly when the image is scaled.

This example corrects that. The idea is to create a Matrix object that represents the inverse of the scaling transformation. Then when the user draws, the program uses the transformation to convert the mouse’s position into the scaled drawing coordinate system so the points can be saved appropriately.

The following code shows how the program declares its transformation matrix.

// Inverse transform to convert mouse coordinates.
private Matrix InverseTransform = new Matrix();

The Matrix class is defined in the System.Drawing.Drawing2D namespace, so the program includes a using System.Drawing.Drawing2D directive to make using the class easier.

When you select a scale, the program calls the following method to prepare to use the new scale. The new code is highlighted in blue.

// Set the scale and redraw.
private void SetScale(float picture_scale)
{
    // Set the scale.
    PictureScale = picture_scale;

    // Resize the PictureBox.
    picCanvas.ClientSize = new Size(
        (int)(WorldWidth * PictureScale),
        (int)(WorldHeight * PictureScale));

    // Prepare the inverse transformation for points.
    InverseTransform = new Matrix();
    InverseTransform.Scale(1.0f / picture_scale, 1.0f / picture_scale);

    // Redraw.
    picCanvas.Refresh();
}

The highlighted code sets InverseTransform to a new Matrix object. It then calls the object’s Scale method to make the matrix represent scaling by the inverse of the current scale factor.

For example, suppose the scale factor is 2. Then the inverse scale factor is 1/2. When the user moves the mouse across the scaled image, the logical location of the mouse in drawing coordinates is twice what it is on the screen because the image is enlarged. When you move the mouse 10 pixels across the screen, you are moving across 20 pixels worth of drawing.

The following code shows the only other pieces of the program that use the inverse transform matrix. Again the changes are highlighted in blue.

// Start drawing.
private void picCanvas_MouseDown(object sender, MouseEventArgs e)
{
    // Create the new polyline.
    NewPolyline = new Polyline();
    Polylines.Add(NewPolyline);

    // Initialize it and add the first point.
    NewPolyline.Color = DrawingColor;
    NewPolyline.Thickness = DrawingThickness;
    NewPolyline.DashStyle = DrawingDashStyle;

    // Transform the point for the current scale.
    Point[] points = { e.Location };
    InverseTransform.TransformPoints(points);
    NewPolyline.Points.Add(points[0]);
}

// Continue drawing.
private void picCanvas_MouseMove(object sender, MouseEventArgs e)
{
    if (NewPolyline == null) return;

    // Transform the point for the current scale.
    Point[] points = { e.Location };
    InverseTransform.TransformPoints(points);
    NewPolyline.Points.Add(points[0]);

    picCanvas.Refresh();
}

The code is similar to the previous version, except this time the program scales the mouse’s position before adding it to the NewPolyline object’s points. To scale the point’s coordinates, the code copies the point into an array and then calls the InverseTransform object’s TransformPoints method to apply the transformation to the array.

The rest of the program is the same as before. Now that the new point is scaled to match the image’s scale factor, the original drawing methods still work.

Download the example to see additional details.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in drawing, files, graphics, serialization, transformations | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | 1 Comment

List strings with a particular style in a Microsoft Word document in C#

[style]

I’m writing a new book and the development editor wants me to make a list of key terms that I specifically want included in the index. I want to include all of the words marked with the style KeyTerm, so I wrote this program to find them.

The program requires a reference to the Word object library. To add the reference in Visual Studio 2008, open Solution Explorer, right-click the References entry, and select Add Reference. Then go to the COM tab and double-click Microsoft Word 14.0 Object Library.

The program’s code uses the following using directive to make using the object library easy.

using Word = Microsoft.Office.Interop.Word;

The following method searches a Word document for words that have a particular style.

// Find words with the given style in the Word file.
private List<string> FindWordsWithStyle(string file_name,
    string word_style)
{
    // Get the Word application object.
    Word._Application word_app = new Word.ApplicationClass();

    // Make Word visible (optional).
    word_app.Visible = false;

    // Open the file.
    object filename = file_name;
    object confirm_conversions = false;
    object read_only = true;
    object add_to_recent_files = false;
    object format = 0;
    object missing = System.Reflection.Missing.Value;

    Word._Document word_doc =
        word_app.Documents.Open(ref filename, ref confirm_conversions,
            ref read_only, ref add_to_recent_files,
            ref missing, ref missing, ref missing, ref missing,
            ref missing, ref format, ref missing, ref missing,
            ref missing, ref missing, ref missing, ref missing);

    // Search.
    List<string> result = new List<string>();
    object style = word_style;
    word_app.Selection.Find.ClearFormatting();
    word_app.Selection.Find.set_Style(ref style);
    object obj_true = true;
    for (;;)
    {
        word_app.Selection.Find.Execute(ref missing,
            ref missing, ref missing, ref missing, ref missing,
            ref missing, ref missing, ref missing, ref obj_true,
            ref missing, ref missing, ref missing, ref missing,
            ref missing, ref missing);
        if (!word_app.Selection.Find.Found) break;
        result.Add(word_app.Selection.Text);
    }

    // Close the document without prompting.
    object save_changes = false;
    word_doc.Close(ref save_changes, ref missing, ref missing);
    word_app.Quit(ref save_changes, ref missing, ref missing);

    // Return the result.
    return result;
}

The method takes as parameters the name of the file to search and the name of the style to locate. The method starts with the usual tasks required to work with Word documents. It creates a Word application object. It then makes some objects holding values that it will use because Word interop generally only works with objects passed by reference. The method then opens the Word document.

Next, the method performs the search. To do that, it uses the Selection object. It first clears the object’s formatting and uses its set_Style method to set the object’s style to the value in the style parameter. It then enters an infinite loop.

Inside the loop, the code calls the Selection object’s Find.Execute method. The only parameter that is not omitted in that method call is the Format property, which indicates whether the method should take into account any formatting specified for the Selection object. This example srets that property to true to make the search look for text that has the desired style.

After calling Find.Execute, the code checks the Selection object’s Find.Found property to see if it found a piece of text with the desired style. If Find.Found is not true, the code breaks out of its loop.

If Find.Found is true, the code adds the text that it found to its result list and continues its loop.

Each time the code calls Find.Execute, that method searches for the next piece of text that matches the style.

After the code breaks out of its loop, it closes the Word document and returns the strings that it found.

Download the example to see additional details such as how the program lets the user browse for the Word document ad how it displays the result.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in books, interoperability, Office, Word | Tagged , , , , , , , , , , , | Leave a comment

Segmented Turning Helper, Version 3

[turning]

John Di Stefano has released version 3 of this free tool Segmented Turning Helper. The program helps you design segmented turning projects such as turned bowls and vases. Here’s the basic description of the tool.

Segmented Turning Helper assists you in creating your segmented turning projects by calculating the segment length of each ring in your project.

The software is easy to use. Input the number of segments, thickness and width of the segment for each ring from your plan drawing and then click the calculate button to calculate the segment length for each ring. A clear, easy to read printout is provided giving segment lengths and a timber stock list.

The software is free and should be used for private use only.
Simply download it to your computer, install it and use it.
Win 10, 8, 7

[WPF 3d]

The new version uses a camera class from my book WPF 3d to provide realiztic 3D rendering. It even uses wood grain textures to make the result look more realistic.

I’m glad you found my book useful, John!


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in 3D, 3D graphics, books, drawing, graphics, wpf | Tagged , , , , , , , , , , , , | Leave a comment

Make a Word document with multiple pages in C#

[Word document]

The example Create a Word document in C# shows how to create a Word document and save it into a file. See that example for the basics including how to create the document, add paragraphs to it, and save it into a file.

This example shows how to make a multi-page Word document. The following snippet shows the key pieces of code.

// Page 1.
// Create a header paragraph.
Word.Paragraph para = word_doc.Paragraphs.Add(ref missing);
para.Range.Text = "First Page";
object heading1_name = "Heading 1";
para.Range.set_Style(ref heading1_name);
para.Range.InsertParagraphAfter();

// Add more text.
para.Range.Text = "Here is some text for the first page.";
para.Range.InsertParagraphAfter();

// Add a page break.
object break_type = Word.WdBreakType.wdPageBreak;
para.Range.InsertBreak(ref break_type);

// Page 2.
// Create a header paragraph.
para = word_doc.Paragraphs.Add(ref missing);
para.Range.Text = "Second Page";
para.Range.set_Style(ref heading1_name);
para.Range.InsertParagraphAfter();

// Add more text.
para.Range.Text = "Here is some text for the second page.";
para.Range.InsertParagraphAfter();

After creating the Word document (not shown), the program creates a Paragraph object. It sets the paragraph’s text to “First Page” and sets its style to “Heading 1.” It then calls the InsertParagraphAfter method to insert a paragraph break after the text. That advances the Paragraph object so it points to the spot after its initial position. In other words, it moves the paragraph after the first line of text and the paragraph break.

Next the code sets the object’s text to some more text.

If you wanted to add more text to the first page, you would repeat these steps:

  • Set the Paragraph object’s text.
  • Optionally set the paragraph’s style.
  • Call InsertParagraphAfter to add a paragraph break.

After finishing the first page, the code calls the InsertBreak method to add a page break. It then repeats the earlier steps to create a second page.

See the earlier example and download this example to see additional details about how to create and save the Word document.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in interoperability, Office, Word | Tagged , , , , , , , , , , , , | Leave a comment

Solve Geometric Problems with C#

[This is a promo piece by Packt, the publisher of my book The Modern C# Challenge. It includes two of the 100 example problems and solutions in the book.]

Solve Geometric Problems with C#

[Solve Geometric Problems with C#]

Learn how to solve C# geometric problems in this article by Rod Stephens, a software developer, consultant, instructor, and author. Rod’s popular C# Helper and VB Helper websites receive millions of hits per year and contain thousands of tips, tricks, and example programs for C# and Visual Basic developers.
Do you wish to test your geometric programming skills?

If your answer is yes, this is the article for you. [This article was taken from Rod’s book The Modern C# Challenge. Some of its chapters] ask you to calculate values such as π or the area below a curve. Others demonstrate useful techniques such as Monte Carlo algorithms. This article will look at two of the prominent geometric programming skills, the Monte Carlo π and Newton’s π. You can also download the example solutions to see additional details and to experiment with the programs at https://github.com/PacktPublishing/The-Modern-CSharp-Challenge/tree/master/Chapter02.

So, let’s get started!

1. Monte Carlo π

A Monte Carlo algorithm uses randomness to approximate the solution to a problem. Often, using more random samples gives you a more accurate approximated solution or gives a greater probability that the solution is correct.

For this problem, use a Monte Carlo algorithm to approximate π. To do this, generate random points in the square (0 ≤ X, Y ≤ 1) and then see how many fall within a circle centered in that square.

Solution:

The following code uses a Monte Carlo algorithm to estimate π:

// Use Monte Carlo simulation to estimate pi.
private double MonteCarloPi(long numPoints)
{
    Random rand = new Random();

    // Make a bitmap to show points.
    int wid = pointsPictureBox.ClientSize.Width;
    int hgt = pointsPictureBox.ClientSize.Height;
    Bitmap bm = new Bitmap(wid, hgt);
    using (Graphics gr = Graphics.FromImage(bm))
    {
        gr.Clear(Color.White);
        gr.DrawEllipse(Pens.Black, 0, 0, wid - 1, hgt - 1);
    }

    // Make the random points.
    int numHits = 0;
    for (int i = 0; i < numPoints; i++)
    {
        // Make a random point 0 <= x < 1.
        double x = rand.NextDouble();
        double y = rand.NextDouble();

        // See how far the point is from (0.5, 0.5).
        double dx = x - 0.5;
        double dy = y - 0.5;
        if (dx * dx + dy * dy < 0.25) numHits++;

        // Plots up to 10,000 points.
        if (i < 10000)
        {
            int ix = (int)(wid * x);
            int iy = (int)(hgt * y);
            if (dx * dx + dy * dy < 0.25)
                bm.SetPixel(ix, iy, Color.Gray);
            else
                bm.SetPixel(ix, iy, Color.Black);
        }
    }

    // Display the plotted points.
    pointsPictureBox.Image = bm;

 
    // Get the hit fraction.
    double fraction = numHits / (double)numPoints;

    // Estimate pi.
    return 4.0 * fraction;
}

The method starts by creating a Random object that it can use to generate random numbers. It then creates a bitmap to fit the program’s PictureBox, associates a Graphics object with it, clears the bitmap, and draws a circle centered in the bitmap.

Next, the code uses a loop to generate the desired number of random points within the square 0 ≤ X, Y < 1. The NextDouble method of the Random class returns a value between 0 and 1, so generating the point’s X and Y coordinates is relatively easy.

The code then determines whether the point lies within the circle that fills the square 0 ≤ X, Y ≤ 1. To do this, the method calculates the distance from the random point to the center of the circle (0.5, 0.5). It then determines whether that distance is less than the circle’s radius.

Actually, the code doesn’t really find the distance between the point and (0.5, 0.5). To do this, it would use the distance formula to find the distance and then use the following equation to determine whether the result is less than the circle’s radius 0.5:

Calculating square roots is relatively slow, however, so the program squares both sides of the equation and uses the following equation instead:

The value 0.5 squared is 0.25, so the program actually tests whether:

The program then plots the point on the bitmap in either gray or black, depending on whether the point lies within the circle. The code also uses the numHits variable to keep track of the number of points that lie within the circle.

After it finishes generating points, the code makes its approximation for π. The square 0 ≤ X, Y ≤ 1 has an area of 1.0 and the circle should have the area π × R2 where R is the circle’s radius. In this example, R is 0.5, so the fraction of points that fall inside the circle should be the following:

If you solve this equation for π, you get the following:

The code gets the fraction of the points that fell within the circle, multiples that by 4.0, and returns the result as its estimate for π.

The following screenshot shows the MonteCarloPi example solution approximating π. After generating 10,000 random points, its approximation for π is off by around 1%. Using more points produces better approximations for π. The result with one million points is correct within about 0.1–0.2%, and the result with 100 million points is correct to within around 0.01%:

2. Newton’s π

Various mathematicians have developed many different ways to approximate π over the years. Sir Isaac Newton devised the following formula to calculate π:

Use Newton’s method to approximate π. Let the user enter the number of terms to calculate. Display the approximation and its error. How does this value compare to the fraction 355/113? Do you need to use checked blocks to protect the code?

Solution:

The following code implements Newton’s method for calculating π:

// Use Newton's formula to calculate pi.
private double NewtonPi(int numTerms)
{
    double total = 0;
    for (int i = 0; i < numTerms; i++)
    {
        total +=
            Factorial(2 * i) /
            Math.Pow(2, 4 * i + 1) /
            (Factorial(i) * Factorial(i)) /
            (2 * i + 1);
    }

    double result = 6 * total;
    Debug.Assert(!double.IsInfinity(result));
    return result;
}

This method simply loops over the desired number of terms, calculates the appropriate term values, and adds them to the result. To allow the program to work with larger values, it uses the following Factorial method:

// Return number!
private double Factorial(int number)
{
    double total = 1;
    for (int i = 2; i <= number; i++) total *= i;
    return total;
}

This is a normal factorial, except it stores its total in a double variable, which can hold larger values than a long variable can.

The value 355/113 is approximately 3.1415929, which is remarkably close to π. Newton’s method converges very quickly on values close to π, only needing nine terms before it is more accurate than 355/113.

This method runs into problems when numTerms is greater than 86. In that case, the value Factorial(2 * i) is too big to fit in a double variable. Because the problem occurs in a double variable instead of an integer, a checked block won’t detect the problem.

As is the case with integers, C# doesn’t notify you if the value doesn’t fit in a double variable. Instead, it sets the variable equal to one of the special values double.Infinity or double.NegativeInfinity. The NewtonPi method uses a Debug.Assert statement to see if this happened.

The lesson to be learned here is that you should use the double.IsInfinity method to check double variables for overflow to infinity or negative infinity if that might be an issue.

Some double calculations, such as total = Math.Sqrt(-1), may result in the special value double.NaN, which stands for Not a Number. You can use the double.IsNaN method to check for that situation.

If you found this article interesting, you can explore The Modern C# Challenge to learn advanced C# concepts and techniques such as building caches, cryptography, and parallel programming by solving interesting programming challenges. The Modern C# Challenge helps you to walk through challenges in C# and explore the .NET Framework in order to develop program logic for real-world applications.

Posted in books, geometry, mathematics | Tagged , , , , , , , , , , | Leave a comment

Pingback: Code Project post “Orbital Mechanics Introduction, Part 2”


[WPF 3d]

The Code Project post Orbital Mechanics Introduction, Part 2 by charles922 uses some code from my WPF 3D posts. His program lets you experiment with the following orbital parameters:

[WPF 3D]

  • Eccentricity – the eccentricity of the orbit’s ellipse.
  • Inclination – the vertical tilt of the ellipse with respect to the orbital plane measured at the ascending node (where the orbit passes upward through the orbital plane).
  • Semi-major Axis – the semi-major axis of the orbit’s ellipse.
  • Longitude of the Ascending Node (Omega, ?) – horizontally orients the ascending node of the ellipse.
  • Argument or Periapsis – defines the orientation of the ellipse in the orbital plane, as an angle measured from the ascending node to the periapsis.

To see Charles’ post, click here.

For LOTS more information on three-dimensional graphics in WPF, see my book WPF 3d,
Three-Dimensional Graphics with WPF and C#
.



Follow me on Twitter   RSS feed   Donate




Posted in 3D, 3D graphics, algorithms, books, drawing, graphics, mathematics, wpf, XAML | Tagged , , , , , , , , , , , , , , | Leave a comment

Quick notes on the recent Windows update


[Windows update]

Recently my computer decided that it needed to perform a bit Windows update. I can usually tell when that’s about to happen because performance is terrible for no obvious reason.

BTW, if you wonder whether an update is impacting performance, open the Start menu and click the Settings tool. Enter “updates” in the search box. Click on the “Check for updates” entry and then click the “Check for updates” button. If an update is pending, that should show its status. For example, if might say that your system is up to date, an update is downloading, an update is pending, or an update is ready to install.

Anyway, the update went pretty smoothly, but it took a really long time–more than four hours. During much of that time, the system was usable but so slow that it wasn’t worth the frustration. Also note that the progress seemed to get stuck a few times. It was still making progress and I could hear the disk working hard, but it showed 85% complete for a long time.

I recommend that you check for updates. If you see that they are available, start the update after you have finished work for the day and let it run overnight. Make sure it’s running correctly and then go watch reruns or something.


Follow me on Twitter   RSS feed   Donate




Posted in system | Tagged , , , , , , , | Leave a comment