Reputation: 455
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:
What am I doing wrong here?
Upvotes: 2
Views: 5107
Reputation: 455
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!
Upvotes: 2
Reputation: 70652
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. I.e. 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.
Upvotes: 3