views:

568

answers:

2

Hi peeps

I've managed to write a 'for dummies' how to calculate the area of irregular polygon in C#, but I need it to be dynamic for any amount of verticies.

Can someone please help?

Class:

public class Vertex
{
    private int _vertexIdx;
    private double _coordX;
    private double _coordY;
    private double _coordZ;

    public Vertex()
    { }

    public Vertex(int vertexIdx, double coordX, double coordY, double coordZ)
    {
        _vertexIdx = vertexIdx;
        _coordX = coordX;
        _coordY = coordY;
        _coordZ = coordZ;
    }

    public int VertexIdx
    {
        get { return _vertexIdx; }
        set { _vertexIdx = value; }
    }

    public double X
    {
        get { return _coordX; }
        set { _coordX = value; }
    }

    public double Y
    {
        get { return _coordY; }
        set { _coordY = value; }
    }

    public double Z
    {
        get { return _coordZ; }
        set { _coordZ = value; }
    }
}

Form_Load:

List<Vertex> verticies = new List<Vertex>();

verticies.Add(new Vertex(1, 930.9729, 802.8789, 0));
verticies.Add(new Vertex(2, 941.5341, 805.662, 0));
verticies.Add(new Vertex(3, 946.5828, 799.271, 0));
verticies.Add(new Vertex(4, 932.6215, 797.0548, 0));

dataGridView1.DataSource = verticies;

Code to calculate when button is pressed: (hard-coded for 4 points polygon - should be for any amount...)

        // X-coords
        double x1;
        double x2;
        double x3;
        double x4;
        double x5;

        // Y-coords
        double y1;
        double y2;
        double y3;
        double y4;
        double y5;

        // Xn * Yn++
        double x1y2;
        double x2y3;
        double x3y4;
        double x4y5;

        // Yn * Xn++
        double y1x2;
        double y2x3;
        double y3x4;
        double y4x5;

        // XnYn++ - YnXn++
        double x1y2my1x2;
        double x2y3my2x3;
        double x3y4my3x4;
        double x4y5my4x5;

        double result;
        double area;

        x1 = Convert.ToDouble(dataGridView1.Rows[0].Cells[1].Value.ToString());
        y1 = Convert.ToDouble(dataGridView1.Rows[0].Cells[2].Value.ToString());
        txtLog.Text += String.Format("X1 = {0}\tY1 = {1}\r\n", x1, y1);

        x2 = Convert.ToDouble(dataGridView1.Rows[1].Cells[1].Value.ToString());
        y2 = Convert.ToDouble(dataGridView1.Rows[1].Cells[2].Value.ToString());
        txtLog.Text += String.Format("X2 = {0}\tY2 = {1}\r\n", x2, y2);

        x3 = Convert.ToDouble(dataGridView1.Rows[2].Cells[1].Value.ToString());
        y3 = Convert.ToDouble(dataGridView1.Rows[2].Cells[2].Value.ToString());
        txtLog.Text += String.Format("X3 = {0}\tY3 = {1}\r\n", x3, y3);

        x4 = Convert.ToDouble(dataGridView1.Rows[3].Cells[1].Value.ToString());
        y4 = Convert.ToDouble(dataGridView1.Rows[3].Cells[2].Value.ToString());
        txtLog.Text += String.Format("X4 = {0}\tY4 = {1}\r\n", x4, y4);

        // add the start point again
        x5 = Convert.ToDouble(dataGridView1.Rows[0].Cells[1].Value.ToString());
        y5 = Convert.ToDouble(dataGridView1.Rows[0].Cells[2].Value.ToString());
        txtLog.Text += String.Format("X5 = {0}\tY5 = {1}\r\n", x5, y5);
        txtLog.Text += "\r\n";

        // Multiply 
        x1y2 = x1 * y2;
        x2y3 = x2 * y3;
        x3y4 = x3 * y4;
        x4y5 = x4 * y5;

        y1x2 = y1 * x2;
        y2x3 = y2 * x3;
        y3x4 = y3 * x4;
        y4x5 = y4 * x5;

        // Subtract from each other
        x1y2my1x2 = x1y2 - y1x2;
        x2y3my2x3 = x2y3 - y2x3; 
        x3y4my3x4 = x3y4 - y3x4;
        x4y5my4x5 = x4y5 - y4x5;

        // Sum all results
        result = x1y2my1x2 + x2y3my2x3 + x3y4my3x4 + x4y5my4x5;
        area = Math.Abs(result / 2);

        txtLog.Text += String.Format("Area = {0}\r\n", area);

Example output:

X1 = 930.9729 Y1 = 802.8789

X2 = 941.5341 Y2 = 805.662

X3 = 946.5828 Y3 = 799.271

X4 = 932.6215 Y4 = 797.0548

X5 = 930.9729 Y5 = 802.8789

Area = 83.2566504099523

+1  A: 

Something like that for a plain polygon (compiled by notepad):

static double GetDeterminant(double x1, double y1, double x2, double y2)
{
    return x1 * y2 - x2 * y1;
}

static double GetArea(IList<Vertex> vertices)
{
    if(vertices.Count < 3)
    {
        return 0;
    }
    double area = GetDeterminant(vertices[vertices.Count - 1].X, vertices[vertices.Count - 1].Y, vertices[0].X, vertices[0].Y);
    for (int i = 1; i < vertices.Count; i++)
    {
        area += GetDeterminant(vertices[i - 1].X, vertices[i - 1].Y, vertices[i].X, vertices[i].Y);
    }
    return area / 2;
}

Although your approach doesn't pay attention to Z-axis. Therefore I'd advice to apply some transformation to get rid of it: you won't be able to get area if the polygon is not plane, whereas if it is plane you are able to get rid of the third dimension.

Li0liQ
so, there is a diffrence between the area calculated in 2D and 3D?
Riaan de Lange
Yes, just a little bit. Area can be calculated for plain objects ONLY. Therefore your polygon MUST be plain - all its vertices should lie in the same plain, otherwise area cannot be calculated. The problem is that this plane won't always be Z=0 plane as in your example. You should take this into consideration and process the points appropriately before calculating the area.
Li0liQ
A: 
        double resultant = 0;
        double area = 0;
        int tel1 = 0;
        int tel2 = 0;

        x1y2lst.Clear();
        y1x2lst.Clear();
        x1y2lstMinusy1x2lst.Clear();

        // *******************************************************************************************//
        // Calculate and populate X1 * Y2 in a list

        for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
        {
            tel1++;
            double x1x = Convert.ToDouble(dataGridView1.Rows[i].Cells[1].Value.ToString());
            double y2y = Convert.ToDouble(dataGridView1.Rows[i+1].Cells[2].Value.ToString());
            x1y2lst.Add(x1x * y2y);
        }
        // Calculate the last with the first value
        double xLastx = Convert.ToDouble(dataGridView1.Rows[tel1].Cells[1].Value.ToString());
        double yFirsty = Convert.ToDouble(dataGridView1.Rows[0].Cells[2].Value.ToString());
        x1y2lst.Add(xLastx * yFirsty);

        // *******************************************************************************************//
        // Calculate and populate Y1 * X2 in a list
        for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
        {
            tel2++;
            double y1y = Convert.ToDouble(dataGridView1.Rows[i].Cells[2].Value.ToString());
            double x2x = Convert.ToDouble(dataGridView1.Rows[i + 1].Cells[1].Value.ToString());
            y1x2lst.Add(y1y * x2x);
        }
        // Calculate the last with the first value
        double yLasty = Convert.ToDouble(dataGridView1.Rows[tel2].Cells[2].Value.ToString());
        double xFirstx = Convert.ToDouble(dataGridView1.Rows[0].Cells[1].Value.ToString());
        y1x2lst.Add(yLasty * xFirstx);

        // Subract List1 values from List2 values
        for (int k = 0; k < x1y2lst.Count; k++)
        {
            x1y2lstMinusy1x2lst.Add(x1y2lst[k] - y1x2lst[k]);
        }

        // Add all answers from previous to a result
        for (int l = 0; l < x1y2lstMinusy1x2lst.Count; l++)
        {
            resultant += x1y2lstMinusy1x2lst[l];
        }
        // Area = Result from steps above devided by 2
        area = Math.Abs(resultant / 2);
        txtArea.Text = Math.Round(area, 4).ToString();
Riaan de Lange