简体   繁体   中英

Producing Points in a Circle with Specific Radius from Central Lat/Long

I need to be able to take a set of lat/lon coordinates and draw a circular "fence" around those coordinates on a map, where the number of points in the circular shape and the radius of the circle are both configurable. My goal is to be able to input the point, the radius of the shape and the number of points I would like it to have and to receive an output containing a List of lat/long coordinates that would complete a shape around the center point if connected.

I've been able to come up with a workable solution that does most of what I need it to, but there are a few things about it that don't work how I expect, and my understanding of the underlying mathematics is weak enough that I'm not sure how to resolve them.

I referenced this post from CSharpHelper to produce the points in a circle around my starting point, and math from this StackOverflow answer to try and convert my miles radius to degrees Lat and Long. Here is the code that I have so far:

public readonly struct LocationPoint
{
    public LocationPoint(double lat, double lon)
    {
        Lat = lat;
        Lon = lon;
    }
        
    public double Lat { get; }
    public double Lon { get; }
}

private static List<LocationPoint> GetZoneCoordinates(LocationPoint center,
                                                      double radiusInMiles,
                                                      int numberOfPoints)
{
    // Convert input miles to degrees latitude and longitude.
    var radiusKm = radiusInMiles * 0.621371;
    var radiusLon = 1 / (111.319 * Math.Cos(center.Lat)) * radiusKm;
    var radiusLat = 1 / 110.574 * radiusKm;
            
    // Calculate amount to increment angle for number of points.
    var dTheta = 2 * Math.PI / numberOfPoints;
    double theta = 0;

    // Produce points.
    var points = new List<LocationPoint>();
    for (var i = 0; i < numberOfPoints; i++)
    {
        points.Add(new LocationPoint
        (
            center.Lat + radiusLat * Math.Sin(theta),
            center.Lon + radiusLon * Math.Cos(theta)
        ));
        theta += dTheta;
    }
            
    return points;
}

The code above works well to create a circular shape with the number of points that I give it. I'll use a center point at JFK International as an example. If I run the above with a radius of.5 miles and 8 points, I get a set of coordinates that map out to the following points:

在此处输入图像描述

There are two things wrong with this shape:

  1. It's a vertical ellipse (though I'm not sure if this is actually a problem, might just be the result of mapping on a sphere and displaying on a 2D map)
  2. The actual radius is much smaller than my input. I in put a radius of.5 miles for the above set of points, and the diameter from right to left is actually closer to.25 miles.

What am I doing wrong here?

Your conversion to km is wrong. var radiusKm = radiusInMiles * 0.621371; should be var radiusKm = radiusInMiles / 0.621371; .

An intuitive way to detect this sort of mistake: one kilometer is a shorter distance than one mile, so for any number of miles, you should have more kilometers than miles. But your formula obviously reduces the original number to something smaller, so that can't be right.

If your original conversion factor comes with units (as it should), another way to detect that sort of mistake is to make sure you include the units in the math. Ie 0.621371 is actually 0.621371 mile/kilometer . When you include the units in your original formula, you wind up with units of mile * mile/kilometer , when what you actually want is just kilometer .

As far as the boundary not being a perfect circle, I would say that yes, that's could be at least partially because of the mapping projection being used at that latitude. Note that the grid lines included on the map also don't form perfect squares, but are stretched out the same way your boundary is. But also keep in mind that the formulae you're using assumes the Earth is a perfect sphere, and it's definitely not. It bulges at the equator as compared to the diameter from pole to pole, and so treating it as a perfect sphere will result in distortions such as you're seeing here.

In case this is helpful to anyone else, I was able to get a very close approximation of a true "great-circle" distance calculation using some of the math in my code above, along with guidance from @PeterDuniho, and now the method outputs coordinates that create a much more uniform circle shape:

private static List<LocationPoint> GetZoneCoordinates(LocationPoint center,
                                                      double radiusInMiles,
                                                      int numberOfPoints)
{
    // Convert input miles to degrees latitude and longitude.
    var radiusKm = radiusInMiles / 0.621371;
    var radiusLon = 1 / (111.319 * Math.Cos(center.Lat * (Math.PI / 180))) * radiusKm;
    var radiusLat = 1 / 110.574 * radiusKm;
            
    // Calculate amount to increment angle for number of points.
    var dTheta = 2 * Math.PI / numberOfPoints;
    double theta = 0;

    // Produce points.
    var points = new List<LocationPoint>();
    for (var i = 0; i < numberOfPoints; i++)
    {
        points.Add(new LocationPoint
        (
            center.Lat + radiusLat * Math.Sin(theta),
            center.Lon + radiusLon * Math.Cos(theta)
        ));
        theta += dTheta;
    }
            
    return points;
}

The difference is on the line where radiusLon is calculated - the cosine of the converted radians of the center point's latitude is being used instead of the raw degrees. I wish I could say that I understand why this makes the difference, but it works well at all of the latitudes I've tried so far.

I will leave Peter's response as the Accepted answer considering that he spotted the most grievous error in my original code. Thanks again for the help!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM