Search code examples
c#google-mapsxamaringeolocation

Polygon area calculation using Latitude and Longitude


I am using a solution I've found in this post: Polygon area calculation using Latitude and Longitude generated from Cartesian space and a world file

Denver football field

There is something wrong because the values I am getting are not real. For example we know a football field should have around 5,300.00 square meters, right? but the calculation is giving 5,759,154.21.

This is the code:

    private static double CalculatePolygonArea(IList<Position> coordinates)
    {
        double area = 0;

        if (coordinates.Count > 2)
        {
            for (var i = 0; i < coordinates.Count - 1; i++)
            {
                Position p1 = coordinates[i];
                Position p2 = coordinates[i + 1];
                area += (ConvertToRadian(p2.Longitude) - ConvertToRadian(p1.Longitude)) * (2 + Math.Sin(ConvertToRadian(p1.Latitude)) + Math.Sin(ConvertToRadian(p2.Latitude)));
            }

            area = area * 6378137 * 6378137 / 2;
        }

        return Math.Abs(area);
    }

    private static double ConvertToRadian(double input)
    {
        return input * Math.PI / 180;
    }

What can be wrong here? Any help?


Solution

  • The area calculation you are using is just plain wrong.... :-/

    I use the SphericalUtil.ComputeSignedArea method from Google's Android Maps Utils.

    Note: Google's Java code for that is under Apache License Version 2.0, and I converted it to C#.

    Looking up that football field up in one of my apps, I get: 4,461, not quite the actual 5,531 but not bad for using Google Map photos...

    enter image description here

    Here is just the ComputeSignedArea:

    public static class SphericalUtil
    {
        const double EARTH_RADIUS = 6371009;
    
        static double ToRadians(double input)
        {
            return input / 180.0 * Math.PI;
        }
    
        public static double ComputeSignedArea(IList<LatLng> path)
        {
            return ComputeSignedArea(path, EARTH_RADIUS);
        }
    
        static double ComputeSignedArea(IList<LatLng> path, double radius)
        {
            int size = path.Count;
            if (size < 3) { return 0; }
            double total = 0;
            var prev = path[size - 1];
            double prevTanLat = Math.Tan((Math.PI / 2 - ToRadians(prev.Latitude)) / 2);
            double prevLng = ToRadians(prev.Longitude);
    
            foreach (var point in path)
            {
                double tanLat = Math.Tan((Math.PI / 2 - ToRadians(point.Latitude)) / 2);
                double lng = ToRadians(point.Longitude);
                total += PolarTriangleArea(tanLat, lng, prevTanLat, prevLng);
                prevTanLat = tanLat;
                prevLng = lng;
            }
            return total * (radius * radius);
        }
    
        static double PolarTriangleArea(double tan1, double lng1, double tan2, double lng2)
        {
            double deltaLng = lng1 - lng2;
            double t = tan1 * tan2;
            return 2 * Math.Atan2(t * Math.Sin(deltaLng), 1 + t * Math.Cos(deltaLng));
        }
    }