Calculate distance of two geo points in km c# - c#

I`d like calculate the distance of two geo points. the points are given in longitude and latitude.
the coordinates are:
point 1: 36.578581, -118.291994
point 2: 36.23998, -116.83171
here a website to compare the results:
http://www.movable-type.co.uk/scripts/latlong.html
here the code I used from this link:
Calculate distance between two points in google maps V3
const double PIx = Math.PI;
const double RADIO = 6378.16;
/// <summary>
/// Convert degrees to Radians
/// </summary>
/// <param name="x">Degrees</param>
/// <returns>The equivalent in radians</returns>
public static double Radians(double x)
{
return x * PIx / 180;
}
/// <summary>
/// Calculate the distance between two places.
/// </summary>
/// <param name="lon1"></param>
/// <param name="lat1"></param>
/// <param name="lon2"></param>
/// <param name="lat2"></param>
/// <returns></returns>
public static double DistanceBetweenPlaces(double lon1, double lat1, double lon2, double lat2)
{
double R = 6371; // km
double dLat = Radians(lat2 - lat1);
double dLon = Radians(lon2 - lon1);
lat1 = Radians(lat1);
lat2 = Radians(lat2);
double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Sin(dLon / 2) * Math.Sin(dLon / 2) * Math.Cos(lat1) * Math.Cos(lat2);
double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
double d = R * c;
return d;
}
Console.WriteLine(DistanceAlgorithm.DistanceBetweenPlaces(36.578581, -118.291994, 36.23998, -116.83171));
the issue is that I get two different results.
my result: 163,307 km
result of the website: 136 km
any suggestions???
torti

Your formula is almost correct, but you have to swap parameters for longitude an latitude
Console.WriteLine(DistanceAlgorithm.DistanceBetweenPlaces(-118.291994, 36.578581, -116.83171, 36.23998)); // = 136 km
I'm using simplified formula:
// cos(d) = sin(φА)·sin(φB) + cos(φА)·cos(φB)·cos(λА − λB),
// where φА, φB are latitudes and λА, λB are longitudes
// Distance = d * R
public static double DistanceBetweenPlaces(double lon1, double lat1, double lon2, double lat2)
{
double R = 6371; // km
double sLat1 = Math.Sin(Radians(lat1));
double sLat2 = Math.Sin(Radians(lat2));
double cLat1 = Math.Cos(Radians(lat1));
double cLat2 = Math.Cos(Radians(lat2));
double cLon = Math.Cos(Radians(lon1) - Radians(lon2));
double cosD = sLat1*sLat2 + cLat1*cLat2*cLon;
double d = Math.Acos(cosD);
double dist = R * d;
return dist;
}
Testing:
(Distance at Equator): Longitudes 0, 100; Latitudes = 0,0; DistanceBetweenPlaces(0, 0, 100, 0) = 11119.5 km
(Distance at North Pole): Longitudes 0, 100; Latitudes = 90,90; DistanceBetweenPlaces(0, 90, 100, 90) = 0 km
Longitudes: -118.291994, -116.83171; Latitudes: 36.578581, 36.23998 = 135.6 km
Longitudes: 36.578581, 36.23998; Latitudes: -118.291994, -116.83171 = 163.2 km
Best regards
P.S. At web site you use for result comparison, for every point first text box is latitude, second - longitude

As you are using the framework 4.0, I would suggest the GeoCoordinate class.
// using System.Device.Location;
GeoCoordinate c1 = new GeoCoordinate(36.578581, -118.291994);
GeoCoordinate c2 = new GeoCoordinate(36.23998, -116.83171);
double distanceInKm = c1.GetDistanceTo(c2) / 1000;
// Your result is: 136,111419742602
You have to add a reference to System.Device.dll.

In my article published several years ago (link: http://www.codeproject.com/Articles/469500/Edumatter-School-Math-Calculators-and-Equation-Sol) I have described 3 useful Functions to calculate the distance between 2 geo-points (in other words, great-circle (orthodromic) distance on Earth between 2 geo-points), which differs in terms of accuracy/performance:
// Haversine formula to calculate great-circle distance between two points on Earth
private const double _radiusEarthMiles = 3959;
private const double _radiusEarthKM = 6371;
private const double _m2km = 1.60934;
private const double _toRad = Math.PI / 180;
/// <summary>
/// Haversine formula to calculate
/// great-circle (orthodromic) distance on Earth
/// High Accuracy, Medium speed
/// </summary>
/// <param name="Lat1">double: 1st point Latitude</param>
/// <param name="Lon1">double: 1st point Longitude</param>
/// <param name="Lat2">double: 2nd point Latitude</param>
/// <param name="Lon2">double: 2nd point Longitude</param>
/// <returns>double: distance in miles</returns>
public static double DistanceMilesHaversine(double Lat1,
double Lon1,
double Lat2,
double Lon2)
{
try
{
double _radLat1 = Lat1 * _toRad;
double _radLat2 = Lat2 * _toRad;
double _dLatHalf = (_radLat2 - _radLat1) / 2;
double _dLonHalf = Math.PI * (Lon2 - Lon1) / 360;
// intermediate result
double _a = Math.Sin(_dLatHalf);
_a *= _a;
// intermediate result
double _b = Math.Sin(_dLonHalf);
_b *= _b * Math.Cos(_radLat1) * Math.Cos(_radLat2);
// central angle, aka arc segment angular distance
double _centralAngle = 2 * Math.Atan2(Math.Sqrt(_a + _b), Math.Sqrt(1 - _a - _b));
// great-circle (orthodromic) distance on Earth between 2 points
return _radiusEarthMiles * _centralAngle;
}
catch { throw; }
}
// Spherical law of cosines formula to calculate great-circle distance between two points on Earth
/// <summary>
/// Spherical Law of Cosines formula to calculate
/// great-circle (orthodromic) distance on Earth;
/// High Accuracy, Medium speed
/// http://en.wikipedia.org/wiki/Spherical_law_of_cosines
/// </summary>
/// <param name="Lat1">double: 1st point Latitude</param>
/// <param name="Lon1">double: 1st point Longitude</param>
/// <param name="Lat2">double: 2nd point Latitude</param>
/// <param name="Lon2">double: 2nd point Longitude</param>
/// <returns>double: distance in miles</returns>
public static double DistanceMilesSLC( double Lat1,
double Lon1,
double Lat2,
double Lon2)
{
try
{
double _radLat1 = Lat1 * _toRad;
double _radLat2 = Lat2 * _toRad;
double _radLon1 = Lon1 * _toRad;
double _radLon2 = Lon2 * _toRad;
// central angle, aka arc segment angular distance
double _centralAngle = Math.Acos(Math.Sin(_radLat1) * Math.Sin(_radLat2) +
Math.Cos(_radLat1) * Math.Cos(_radLat2) * Math.Cos(_radLon2 - _radLon1));
// great-circle (orthodromic) distance on Earth between 2 points
return _radiusEarthMiles * _centralAngle;
}
catch { throw; }
}
// Great-circle distance calculation using Spherical Earth projection formula**
/// <summary>
/// Spherical Earth projection to a plane formula (using Pythagorean Theorem)
/// to calculate great-circle (orthodromic) distance on Earth.
/// http://en.wikipedia.org/wiki/Geographical_distance
/// central angle =
/// Sqrt((_radLat2 - _radLat1)^2 + (Cos((_radLat1 + _radLat2)/2) * (Lon2 - Lon1))^2)
/// Medium Accuracy, Fast,
/// relative error less than 0.1% in search area smaller than 250 miles
/// </summary>
/// <param name="Lat1">double: 1st point Latitude</param>
/// <param name="Lon1">double: 1st point Longitude</param>
/// <param name="Lat2">double: 2nd point Latitude</param>
/// <param name="Lon2">double: 2nd point Longitude</param>
/// <returns>double: distance in miles</returns>
public static double DistanceMilesSEP(double Lat1,
double Lon1,
double Lat2,
double Lon2)
{
try
{
double _radLat1 = Lat1 * _toRad;
double _radLat2 = Lat2 * _toRad;
double _dLat = (_radLat2 - _radLat1);
double _dLon = (Lon2 - Lon1) * _toRad;
double _a = (_dLon) * Math.Cos((_radLat1 + _radLat2) / 2);
// central angle, aka arc segment angular distance
double _centralAngle = Math.Sqrt(_a * _a + _dLat * _dLat);
// great-circle (orthodromic) distance on Earth between 2 points
return _radiusEarthMiles * _centralAngle;
}
catch { throw; }
}
Functions return results in miles; to find the distance in km multiply the result by 1.60934 (see private const double _m2km = 1.60934).
Pertinent to the sample: find the distance point1 (36.578581, -118.291994) and point2 (36.23998, -116.83171) the three aforementioned Function produced the following results (km):
136.00206654936932
136.00206654937023
136.00374497149613
and the calculator (link: http://www.movable-type.co.uk/scripts/latlong.html) gave the result: 136.0
Hope this may help. Best regards,

I used the formula from Wikipedia and put it in a lambda function:
Func<double, double, double, double, double> CalcDistance = (lat1, lon1, lat2, lon2) =>
{
Func<double, double> Radians = (angle) =>
{
return angle * (180.0 / Math.PI);
};
const double radius = 6371;
double delataSigma = Math.Acos(Math.Sin(Radians(lat1)) * Math.Sin(Radians(lat2)) +
Math.Cos(Radians(lat1)) * Math.Cos(Radians(lat2)) * Math.Cos(Math.Abs(Radians(lon2) - Radians(lon1))));
double distance = radius * delataSigma;
return distance;
};

try this... I have used this is apps before -- its pretty accurate. Forgive me for not giving due credit to the brilliant soul who originally published this, I transposed it from java to C#:
namespace Sample.Geography
{
using System;
public class GeodesicDistance
{
private static double DegsToRadians(double degrees)
{
return (0.017453292519943295 * degrees);
}
public static double? GetDistance(double lat1, double lon1, double lat2, double lon2)
{
long num = 0x615299L;
double num2 = 6356752.3142;
double num3 = 0.0033528106647474805;
double num4 = DegsToRadians(lon2 - lon1);
double a = Math.Atan((1 - num3) * Math.Tan(DegsToRadians(lat1)));
double num6 = Math.Atan((1 - num3) * Math.Tan(DegsToRadians(lat2)));
double num7 = Math.Sin(a);
double num8 = Math.Sin(num6);
double num9 = Math.Cos(a);
double num10 = Math.Cos(num6);
double num11 = num4;
double num12 = 6.2831853071795862;
int num13 = 20;
double y = 0;
double x = 0;
double num18 = 0;
double num20 = 0;
double num22 = 0;
while ((Math.Abs((double) (num11 - num12)) > 1E-12) && (--num13 > 0))
{
double num14 = Math.Sin(num11);
double num15 = Math.Cos(num11);
y = Math.Sqrt(((num10 * num14) * (num10 * num14)) + (((num9 * num8) - ((num7 * num10) * num15)) * ((num9 * num8) - ((num7 * num10) * num15))));
if (y == 0)
{
return 0;
}
x = (num7 * num8) + ((num9 * num10) * num15);
num18 = Math.Atan2(y, x);
double num19 = ((num9 * num10) * num14) / y;
num20 = 1 - (num19 * num19);
if (num20 == 0)
{
num22 = 0;
}
else
{
num22 = x - (((2 * num7) * num8) / num20);
}
double num21 = ((num3 / 16) * num20) * (4 + (num3 * (4 - (3 * num20))));
num12 = num11;
num11 = num4 + ((((1 - num21) * num3) * num19) * (num18 + ((num21 * y) * (num22 + ((num21 * x) * (-1 + ((2 * num22) * num22)))))));
}
if (num13 == 0)
{
return null;
}
double num23 = (num20 * ((num * num) - (num2 * num2))) / (num2 * num2);
double num24 = 1 + ((num23 / 16384) * (4096 + (num23 * (-768 + (num23 * (320 - (175 * num23)))))));
double num25 = (num23 / 1024) * (256 + (num23 * (-128 + (num23 * (74 - (47 * num23))))));
double num26 = (num25 * y) * (num22 + ((num25 / 4) * ((x * (-1 + ((2 * num22) * num22))) - ((((num25 / 6) * num22) * (-3 + ((4 * y) * y))) * (-3 + ((4 * num22) * num22))))));
return new double?((num2 * num24) * (num18 - num26));
}
}
}

I just tried to code at GeoDataSource, and it worked perfectly well:
http://www.geodatasource.com/developers/c-sharp

I think you are interchanging latitude and longitude values. Try correcting those or change sequence of parameters.

Related

How to get all points between two geo coordinates

I have two geo positions lets say A and B and distance between both of them say D.
So I know A, B, and D.
Now I want to get all the points (l,m,n,o... etc.) in a distance of 3 meters each.
Note:
If I draw a straight line between A and B then all the required points should lie on that straight line.
What I have done so far:
I have searched a lot and come across this website but there is an example which is in javascript and when I converted this code into c# then I do not get exact points.
Please help me! Thank you!
For those who believe this question as a duplicate for like this then I want to clarify that I do not need to calculate distance. In my question distance is already known.
Finally, I came across the following Code:
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
namespace Calc
{
public static class Program
{
private static readonly long RADIUS_OF_EARTH = 6371000; // radius of earth in m
public static void Main(string[] args)
{
// point interval in meters
int interval =2;
// direction of line in degrees
//start point
double lat1 = 28.6514975008004;
double lng1 = 77.2216437757015;
// end point
double lat2 = 28.6514763167883;
double lng2 = 77.2221480309963;
MockLocation start = new MockLocation(lat1, lng1);
MockLocation end = new MockLocation(lat2, lng2);
double azimuth = calculateBearing(start, end);
Console.WriteLine(azimuth);
List<MockLocation> coords = getLocations(interval, azimuth, start, end);
foreach (MockLocation mockLocation in coords)
{
Console.WriteLine(mockLocation.lat + ", " + mockLocation.lng);
}
Console.ReadLine();
}
/**
* returns every coordinate pair in between two coordinate pairs given the desired interval
* #param interval
* #param azimuth
* #param start
* #param end
* #return
*/
private static List<MockLocation> getLocations(int interval, double azimuth, MockLocation start, MockLocation end)
{
Console.WriteLine("getLocations: " +
"\ninterval: " + interval +
"\n azimuth: " + azimuth +
"\n start: " + start.toString());
double d = getPathLength(start, end);
int dist = (int)d / interval;
int coveredDist = interval;
List<MockLocation> coords = new List<MockLocation>();
MockLocation mock = new MockLocation(start.lat, start.lng);
coords.Add(mock);
for (int distance = 0; distance < dist; distance += interval)
{
MockLocation coord = getDestinationLatLng(start.lat, start.lng, azimuth, coveredDist);
coveredDist += interval;
coords.Add(coord);
}
coords.Add(new MockLocation(end.lat, end.lng));
return coords;
}
public static double ToRadians(this double val)
{
return (Math.PI / 180) * val;
}
/**
* calculates the distance between two lat, long coordinate pairs
* #param start
* #param end
* #return
*/
private static double getPathLength(MockLocation start, MockLocation end)
{
double lat1Rads = ToRadians(start.lat);
double lat2Rads = ToRadians(end.lat);
double deltaLat = ToRadians(end.lat - start.lat);
double deltaLng = ToRadians(end.lng - start.lng);
double a = Math.Sin(deltaLat / 2) * Math.Sin(deltaLat / 2) + Math.Cos(lat1Rads) * Math.Cos(lat2Rads) * Math.Sin(deltaLng / 2) * Math.Sin(deltaLng / 2);
double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
double d = RADIUS_OF_EARTH * c;
return d;
}
/**
* returns the lat an long of destination point given the start lat, long, aziuth, and distance
* #param lat
* #param lng
* #param azimuth
* #param distance
* #return
*/
private static MockLocation getDestinationLatLng(double lat, double lng, double azimuth, double distance)
{
double radiusKm = RADIUS_OF_EARTH / 1000; //Radius of the Earth in km
double brng = ToRadians(azimuth); //Bearing is degrees converted to radians.
double d = distance / 1000; //Distance m converted to km
double lat1 = ToRadians(lat); //Current dd lat point converted to radians
double lon1 = ToRadians(lng); //Current dd long point converted to radians
double lat2 = Math.Asin(Math.Sin(lat1) * Math.Cos(d / radiusKm) + Math.Cos(lat1) * Math.Sin(d / radiusKm) * Math.Cos(brng));
double lon2 = lon1 + Math.Atan2(Math.Sin(brng) * Math.Sin(d / radiusKm) * Math.Cos(lat1), Math.Cos(d / radiusKm) - Math.Sin(lat1) * Math.Sin(lat2));
//convert back to degrees
lat2 = ToDegrees(lat2);
lon2 = ToDegrees(lon2);
return new MockLocation(lat2, lon2);
}
/**
* calculates the azimuth in degrees from start point to end point");
double startLat = ToRadians(start.lat);
* #param start
* #param end
* #return
*/
private static double calculateBearing(MockLocation start, MockLocation end)
{
double startLat = ToRadians(start.lat);
double startLong = ToRadians(start.lng);
double endLat = ToRadians(end.lat);
double endLong = ToRadians(end.lng);
double dLong = endLong - startLong;
double dPhi = Math.Log(Math.Tan((endLat / 2.0) + (Math.PI / 4.0)) / Math.Tan((startLat / 2.0) + (Math.PI / 4.0)));
if (Math.Abs(dLong) > Math.PI)
{
if (dLong > 0.0)
{
dLong = -(2.0 * Math.PI - dLong);
}
else
{
dLong = (2.0 * Math.PI + dLong);
}
}
double bearing = (ToDegrees(Math.Atan2(dLong, dPhi)) + 360.0) % 360.0;
return bearing;
}
public static double ToDegrees(double radians)
{
double degrees = (180 / Math.PI) * radians;
return (degrees);
}
public class MockLocation
{
public double lat;
public double lng;
public MockLocation(double lat, double lng)
{
this.lat = lat;
this.lng = lng;
}
public string toString()
{
return (lat + "," + lng).ToString();
}
}
}
}
I hope this will help other learners.

Divide Geo Line in specified interval based on start and end geo-coordinates

I have two geo coordinates (Start and End Points) and I am able to create a line between them. Suppose these two coordinates are at a distance of 30 meters then I need to find every geolocation of points at an interval of 3 meters. So there are 10 such points which are required.
I am able to find the points by some formulas but these points are not in the same direction as the line formed by start and end points.
What I have done so far is below...
using System;
namespace Test
{
public class AzimuthCalculator
{
public const double range = 0.00186411F; // in Miles
public const double rangeInMeter = 3F;
public const double factor = 0.003F;
public static void Main(String[] args)
{
double sLatitude = 28.6187763214111F;
double sLongitude = 77.2093048095703F;
double eLatitude = 28.6191763153134F;
double eLongitude = 77.2097146511078F;
Console.WriteLine($"Start Point : {sLatitude}, {sLongitude}");
Console.WriteLine($"End Point : {eLatitude},{eLongitude}");
double distance = CalculateDistance(sLatitude, sLongitude, eLatitude, eLongitude);
Console.WriteLine($"Distance : {distance} miles, {MilesToMeter(distance)} meter, {(distance * 1.60934)} kilometer");
distance = distance * 1.60934;
double numberOfIDS = distance/factor;
double azimuthAngle = DegreeBearing(sLatitude, sLongitude, eLatitude, eLongitude);
Console.WriteLine($"Azimuth : {azimuthAngle}");
Console.WriteLine($"IDS : {numberOfIDS}");
double constantAzimuth = (azimuthAngle/numberOfIDS);
azimuthAngle = constantAzimuth;
Console.WriteLine($"Original Azimuth : {azimuthAngle}");
double[] getAnotherPoint = pointRadialDistance(sLatitude, sLongitude, azimuthAngle, distance);
Console.WriteLine($"End Point : {getAnotherPoint[0]},{getAnotherPoint[1]}");
distance = 0.003; // 3 meter
getAnotherPoint = pointRadialDistance(sLatitude, sLongitude, azimuthAngle, distance);
int totalIDS = (Int32)(numberOfIDS);
for(int i=0;i<totalIDS;i++)
{
sLatitude = getAnotherPoint[0];
sLongitude = getAnotherPoint[1];
distance = 0.003;
Console.WriteLine($"new PointLatLng({getAnotherPoint[0]},{getAnotherPoint[1]}),");
getAnotherPoint = pointRadialDistance(sLatitude, sLongitude, azimuthAngle, distance);
}
Console.ReadLine();
}
static double rEarth = 6371.01F; // Earth radius in km
static double epsilon = 0.000001F;
public static double[] pointRadialDistance(double lat1, double lon1, double bearing, double distance)
{
double rlat1 = ToRad(lat1);
double rlon1 = ToRad(lon1);
double rbearing = ToRad(bearing);
double rdistance = distance / rEarth; // normalize linear distance to radian angle
double rlat = Math.Asin( Math.Sin(rlat1) * Math.Cos(rdistance) + Math.Cos(rlat1) * Math.Sin(rdistance) * Math.Cos(rbearing));
double rlon = 0.0F;
if ( Math.Cos(rlat) == 0 || Math.Abs(Math.Cos(rlat)) < epsilon) // Endpoint a pole
rlon=rlon1;
else
rlon = ((rlon1 - Math.Asin( Math.Sin(rbearing) * Math.Sin(rdistance) / Math.Cos(rlat) ) + Math.PI ) % (2*Math.PI) ) - Math.PI;
double lat = ToDegrees(rlat);
double lon = ToDegrees(rlon);
double[] listNew = new double[2];
listNew[0] = lat;
listNew[1] = lon;
return (listNew);
}
public static GeoLocation FindPointAtDistanceFrom(GeoLocation startPoint, double initialBearingRadians, double distanceKilometres)
{
const double radiusEarthKilometres = 6371.01;
var distRatio = distanceKilometres / radiusEarthKilometres;
var distRatioSine = Math.Sin(distRatio);
var distRatioCosine = Math.Cos(distRatio);
var startLatRad = DegreesToRadians(startPoint.Latitude);
var startLonRad = DegreesToRadians(startPoint.Longitude);
var startLatCos = Math.Cos(startLatRad);
var startLatSin = Math.Sin(startLatRad);
var endLatRads = Math.Asin((startLatSin * distRatioCosine) + (startLatCos * distRatioSine * Math.Cos(initialBearingRadians)));
var endLonRads = startLonRad
+ Math.Atan2(
Math.Sin(initialBearingRadians) * distRatioSine * startLatCos,
distRatioCosine - startLatSin * Math.Sin(endLatRads));
return new GeoLocation
{
Latitude = RadiansToDegrees(endLatRads),
Longitude = RadiansToDegrees(endLonRads)
};
}
public struct GeoLocation
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
public static double DegreesToRadians(double degrees)
{
const double degToRadFactor = Math.PI / 180;
return degrees * degToRadFactor;
}
public static double RadiansToDegrees(double radians)
{
const double radToDegFactor = 180 / Math.PI;
return radians * radToDegFactor;
}
public static double CalculateDistance(double sLatitude, double sLongitude, double eLatitude, double eLongitude)
{
var radiansOverDegrees = (Math.PI / 180.0);
var sLatitudeRadians = sLatitude * radiansOverDegrees;
var sLongitudeRadians = sLongitude * radiansOverDegrees;
var eLatitudeRadians = eLatitude * radiansOverDegrees;
var eLongitudeRadians = eLongitude * radiansOverDegrees;
var dLongitude = eLongitudeRadians - sLongitudeRadians;
var dLatitude = eLatitudeRadians - sLatitudeRadians;
var result1 = Math.Pow(Math.Sin(dLatitude / 2.0), 2.0) + Math.Cos(sLatitudeRadians) * Math.Cos(eLatitudeRadians) * Math.Pow(Math.Sin(dLongitude / 2.0), 2.0);
// Using 3956 as the number of miles around the earth
var result2 = 3956.0 * 2.0 * Math.Atan2(Math.Sqrt(result1), Math.Sqrt(1.0 - result1));
return result2;
}
static double DegreeBearing(double lat1, double lon1,double lat2, double lon2)
{
var dLon = ToRad(lon2 - lon1);
var dPhi = Math.Log(Math.Tan(ToRad(lat2) / 2 + Math.PI / 4) / Math.Tan(ToRad(lat1) / 2 + Math.PI / 4));
if (Math.Abs(dLon) > Math.PI)
dLon = dLon > 0 ? - (2 * Math.PI - dLon) : (2 * Math.PI + dLon);
return ToBearing(Math.Atan2(dLon, dPhi));
}
public static double ToRad(double degrees)
{
return degrees * (Math.PI / 180);
}
public static double ToDegrees(double radians)
{
return radians * 180 / Math.PI;
}
public static double ToBearing(double radians)
{
// convert radians to degrees (as bearing: 0...360)
return (ToDegrees(radians) + 360) % 360;
}
public static double MeterToMiles(double meter)
{
return (meter / 1609.344);
}
public static double MilesToMeter(double miles)
{
return (miles * 1609.344);
}
}
}
Why do you calculate wrong bearing from right one here constantAzimuth = (azimuthAngle/numberOfIDS); and use it later?
You can calculate intermediate points on the great circle path using approach described here (essentially it is SLERP - spherical linear interpolation)
Formula:
a = sin((1−f)⋅δ) / sin δ
b = sin(f⋅δ) / sin δ
x = a ⋅ cos φ1 ⋅ cos λ1 + b ⋅ cos φ2 ⋅ cos λ2
y = a ⋅ cos φ1 ⋅ sin λ1 + b ⋅ cos φ2 ⋅ sin λ2
z = a ⋅ sin φ1 + b ⋅ sin φ2
φi = atan2(z, √x² + y²)
λi = atan2(y, x)
where
f is fraction along great circle route (f=0 is point 1, f=1 is point 2),
δ is the angular distance d/R between the two points.

Unit Test - sometimes works, sometimes not

I have a unit test below running against the code that follows. This test sometimes passes, sometimes fails. Not sure why and hesitate to change things radically since well, it is a formula and sometimes passes...I'm thinking it may have something to do with the precision of the type double? Not sure. Thoughts?
[TestMethod]
public void CircleFromCircumference()
{
var random = new Random();
var circumference = random.NextDouble();
var circle = new Circle("My circle", circumference, Circle.CircleDimensions.Circumference);
var var1 = circumference - circle.Circumference;
var var2 = circumference - 2 * Math.PI * circle.Radius;
var var3 = circumference - Math.PI * circle.Diameter;
var var4 = Math.Pow(circumference / (2 * Math.PI), 2) * Math.PI - circle.Area;
Assert.IsTrue(
circumference - circle.Circumference <= 0 //circumference
&& circumference - 2 * Math.PI * circle.Radius <= 0 //radius
&& circumference - Math.PI * circle.Diameter <= 0 //diameter
&& Math.Pow(circumference / (2 * Math.PI), 2) * Math.PI - circle.Area <= 0 //area
&& string.IsNullOrEmpty(circle.ShapeException));
}
using System;
using System.Runtime.Serialization;
namespace Shapes
{
[DataContract]
public class Circle : Shape
{
[DataMember] public double Radius { get; set; }
[DataMember] public double Diameter { get; set; }
[DataMember] public double Circumference { get; set; }
/// <summary>
/// The name of the value you are sending. Radius is the default
/// </summary>
public enum CircleDimensions
{
Circumference = 1,
Area = 2,
Diameter = 3
}
/// <summary>
///
/// </summary>
/// <param name="circleName">The name of your circle</param>
/// <param name="dimension">The value of the dimension you are providing</param>
/// <param name="circleDimensions">The name of the value you are providing. Radius is default</param>
public Circle(string circleName, double dimension = 0, CircleDimensions circleDimensions = 0)
{
this.ShapeName = circleName;
if (dimension <= 0)
{
this.ShapeException = "Parameters must be greater than zero";
return;
}
switch (circleDimensions)
{
case CircleDimensions.Circumference:
//radius from Circumference
this.Circumference = dimension;
this.Radius = this.RadiusFromCircumference(dimension);
this.Area = this.CalculateArea(this.Radius);
this.Diameter = this.CalculateDiameter(this.Radius);
break;
case CircleDimensions.Area:
//radius from Area
break;
case CircleDimensions.Diameter:
//radius from diameter
break;
default: //calculate from radius
this.Radius = dimension;
this.Diameter = this.CalculateDiameter(dimension);
this.Circumference = this.CalculateCircumference(dimension);
this.Area = this.CalculateArea(dimension);
break;
}
}
private double RadiusFromCircumference(double dimension) => dimension / (2 * Math.PI);
private double CalculateCircumference(double dimension) => 2 * Math.PI * dimension;
private double CalculateDiameter(double dimension) => 2 * dimension;
private double CalculateArea(double dimension) =>
Math.PI * (Math.Pow(dimension, 2));
}
}
The inconsistency has nothing to do with precision per se, it has more to do with how floating point representation works. For example, if you write this:
for (float f = 0.0f; f != 1.0f; f+=0.1f)
{
Console.WriteLine(f);
}
It will never exit. Because 0.1 does not have an exact representation in binary form. (https://www.exploringbinary.com/why-0-point-1-does-not-exist-in-floating-point/). I also recommend reading (https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html)
Back to the problem at hand, in your code, you are getting the Radius using this :
dimension / (2 * Math.PI); //passed in dimension is the Circumference, returns radius
And then in your test you are asserting that:
circumference - 2 * Math.PI * circle.Radius <= 0
Dividing and then multiplying by the same floating point number is not guaranteed to give you the original floating point number as a result.
Thus, it is a bad idea in general to assert this. The most common way to test "almost equality" is to test equality "within limits". In your case, all you have to do is define a small enough epsilon that you deem "acceptable", greater or equal to double.Epsilon in your tests.
var epsilon = double.Epsilon;
Assert.IsTrue(
Math.Abs(circumference - circle.Circumference) <= epsilon //circumference
&& Math.Abs(circumference - 2 * Math.PI * circle.Radius) <= epsilon //radius
&& Math.Abs(circumference - Math.PI * circle.Diameter) <= epsilon //diameter
&& Math.Abs(Math.Pow(circumference / (2 * Math.PI), 2) * Math.PI - circle.Area) <= epsilon //area
&& string.IsNullOrEmpty(circle.ShapeException));
If instead you have to guarantee exactness, one option is to switch to a non-floating point type like decimal, but expect a performance hit.

Adding distance to a GPS coordinate

I'm trying to generate some points at random distances away from a fixed point using GPS.
How can I add distance in meters to a GPS coordinate?
I've looked at UTM to GPS conversion but is there a simpler method to achieve this?
I'm working on Android platform just in case.
Cheers,
fgs
P0(lat0,lon0) : initial position (unit : degrees)
dx,dy : random offsets from your initial position in meters
You can use an approximation to compute the position of the randomized position:
lat = lat0 + (180/pi)*(dy/6378137)
lon = lon0 + (180/pi)*(dx/6378137)/cos(lat0)
This is quite precise as long as the random distance offset is below 10-100 km
Edit: of course in Java Math.cos() expects radians so do use Math.cos(Math.PI/180.0*lat0) if lat0 is in degrees as assumed above.
To take a square I'm using this:
private double[] getBoundingBox(final double pLatitude, final double pLongitude, final int pDistanceInMeters) {
final double[] boundingBox = new double[4];
final double latRadian = Math.toRadians(pLatitude);
final double degLatKm = 110.574235;
final double degLongKm = 110.572833 * Math.cos(latRadian);
final double deltaLat = pDistanceInMeters / 1000.0 / degLatKm;
final double deltaLong = pDistanceInMeters / 1000.0 / degLongKm;
final double minLat = pLatitude - deltaLat;
final double minLong = pLongitude - deltaLong;
final double maxLat = pLatitude + deltaLat;
final double maxLong = pLongitude + deltaLong;
boundingBox[0] = minLat;
boundingBox[1] = minLong;
boundingBox[2] = maxLat;
boundingBox[3] = maxLong;
return boundingBox;
}
This returns an array with 4 coordinates, with them you can make a square with your original point in center.
A detailed outline is given at http://www.movable-type.co.uk/scripts/latlong.html.
If you, somewhere, need to interconvert longitude/latitude to UTM coordinates (the ones used in GPS) you may want to have a look at http://www.uwgb.edu/dutchs/UsefulData/UTMFormulas.htm
If you want to go east or north or west or south you can use this:
#SuppressLint("DefaultLocale")
public static double go_mock_loc(double xx_lat,double xx_long,double xx_dinstance,String Direction)
{
// double xx_lat= 45.815005;
// double xx_long= 15.978501;
// int xx_dinstance=500;
int equator_circumference=6371000;
int polar_circumference=6356800;
double m_per_deg_long = 360 / polar_circumference;
double rad_lat=(xx_lat* (Math.PI) / 180);
double m_per_deg_lat = 360 / ( Math.cos(rad_lat) * equator_circumference);
double deg_diff_long = xx_dinstance * m_per_deg_long;
double deg_diff_lat = xx_dinstance * m_per_deg_lat;
double xx_north_lat = xx_lat + deg_diff_long;
//double xx_north_long= xx_long;
double xx_south_lat = xx_lat - deg_diff_long;
//double xx_south_long= xx_long;
//double xx_east_lat = xx_lat;
double xx_east_long= xx_long + deg_diff_lat;
//double xx_west_lat = xx_lat;
double xx_west_long= xx_long - deg_diff_lat;
if (Direction.toUpperCase().contains("NORTH")) {
return xx_north_lat;
} else if (Direction.toUpperCase().contains("SOUTH"))
{
return xx_south_lat;
} else if (Direction.toUpperCase().contains("EAST"))
{
return xx_east_long;
} else if (Direction.toUpperCase().contains("WEST"))
{
return xx_west_long;
}
else
return 0;
}
I found that solution of #Bogdan Khrystov is very well.
So here is C# version of his solution.
public enum GeoDirection
{
NORTH = 1, SOUTH = 2, EAST = 3, WEST = 4
}
public static Tuple<double, double> AddDistanceInMeters(double latitude, double longitude, int distanceInMeters, GeoDirection direction)
{
var equatorCircumference = 6371000;
var polarCircumference = 6356800;
var mPerDegLong = 360 / (double)polarCircumference;
var radLat = latitude * Math.PI / 180;
var mPerDegLat = 360 / (Math.Cos(radLat) * equatorCircumference);
var degDiffLong = distanceInMeters * mPerDegLong;
var degDiffLat = distanceInMeters * mPerDegLat;
var xxNorthLat = latitude + degDiffLong;
var xxSouthLat = latitude - degDiffLong;
var xxEastLong = longitude + degDiffLat;
var xxWestLong = longitude - degDiffLat;
switch (direction)
{
case GeoDirection.NORTH:
return new Tuple<double, double>(xxNorthLat, longitude);
case GeoDirection.SOUTH:
return new Tuple<double, double>(xxSouthLat, longitude);
case GeoDirection.EAST:
return new Tuple<double, double>(latitude, xxEastLong);
case GeoDirection.WEST:
return new Tuple<double, double>(latitude, xxWestLong);
default:
return null;
}
}
rewrite #Ersin Gülbahar answer in Kotlin:
object LocationUtil {
enum class Direction {
NORTH, SOUTH, EAST, WEST
}
fun addDistanceInMeters(
latitude: Double,
longitude: Double,
distanceInMeters: Int,
direction: Direction
): Pair<Double, Double> {
val equatorCircumference = 6371000
val polarCircumference = 6356800
val mPerDegLong = (360 / polarCircumference.toDouble())
val radLat = latitude * Math.PI / 180
val mPerDegLat = 360 / (Math.cos(radLat) * equatorCircumference)
val degDiffLong = distanceInMeters * mPerDegLong
val degDiffLat = distanceInMeters * mPerDegLat
val xxNorthLat = latitude + degDiffLong
val xxSouthLat = latitude - degDiffLong
val xxEastLong = longitude + degDiffLat
val xxWestLong = longitude - degDiffLat
return when (direction) {
Direction.NORTH -> Pair(xxNorthLat, longitude)
Direction.SOUTH -> Pair(xxSouthLat, longitude)
Direction.EAST -> Pair(latitude, xxEastLong)
Direction.WEST -> Pair(latitude, xxWestLong)
}
}
}
This code splits the line between two coordinates in n segments. Replace the delta calculation by your fixed distance
#Override
public void split(Coordinates p1, Coordinates p2, int segments) {
double φ1 = Math.toRadians(p1.getLat());
double λ1 = Math.toRadians(p1.getLon());
double φ2 = Math.toRadians(p2.getLat());
double λ2 = Math.toRadians(p2.getLon());
double xDelta = (φ2 - φ1) / segments;
double yDelta = (λ2 - λ1) / segments;
for (int i = 0; i < segments; i++){
double x = φ1 + i * xDelta;
double y = λ1 + i * yDelta;
double xc = Math.toDegrees(x);
double yc = Math.toDegrees(y);
System.out.println(xc+","+yc);
}
}
Combining answers from #Ersin Gülbahar and #Stéphane above, I came up with this solution in Flutter/Dart:
import 'dart:math' as math;
enum Direction { north, south, east, west }
double moveCoordinate(
double latitude, double longitude, double distanceToMoveInMeters, Direction directionToMove) {
const earthEquatorRadius = 6378137;
final latitudeOffset = (180 / math.pi) * (distanceToMoveInMeters / earthEquatorRadius);
final longitudeOffset = (180 / math.pi) *
(distanceToMoveInMeters / earthEquatorRadius) /
math.cos(math.pi / 180 * latitude);
switch (directionToMove) {
case Direction.north:
return latitude + latitudeOffset;
case Direction.south:
return latitude - latitudeOffset;
case Direction.east:
return longitude + longitudeOffset;
case Direction.west:
return longitude - longitudeOffset;
}
return 0;
}
This works, tested. The code is C# but you can easily change it to another language
private PointLatLng NewPositionBasedOnDistanceAngle(PointLatLng org, double distance, double bearing)
{
double rad = bearing * Math.PI / 180; //to radians
double lat1 = org.Lat * Math.PI / 180; //to radians
double lng1 = org.Lng * Math.PI / 180; //to radians
double lat = Math.Asin(Math.Sin(lat1) * Math.Cos(distance / 6378137) + Math.Cos(lat1) * Math.Sin(distance / 6378137) * Math.Cos(rad));
double lng = lng1 + Math.Atan2(Math.Sin(rad) * Math.Sin(distance / 6378137) * Math.Cos(lat1), Math.Cos(distance / 6378137) - Math.Sin(lat1) * Math.Sin(lat));
return new PointLatLng(lat * 180 / Math.PI, lng * 180 / Math.PI); // to degrees
}

How do I find the lat/long that is x km north of a given lat/long?

I have some C# code that generates google maps. This codes looks at all the Points I need to plot on the map and then works out the Bounds of a rectangle to include those points. It then passes this bounds to the Google Maps API to set the zoom level appropriately to show all of the points on the map.
This code is working fine however I have a new requirement.
One of the points may have a precision associated with it. If this is the case then I draw a circle around the point with the radius set to the precision value. Again this works fine however my bounds checking is now not doing what I want it to do. I want to have the bounding box include the complete circle.
This requires an algorithm to take a point x and calculate the point y that would be z metres north of x and also z metres south of x.
Does anyone have this algorithm, preferably in C#. I did find a generic algorithm here but I appear to have not implemented this correctly as the answers I am getting are 1000s of km adrift.
This is the Generic example
Lat/lon given radial and distance
A point {lat,lon} is a distance d out on the tc radial from point 1 if:
lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
IF (cos(lat)=0)
lon=lon1 // endpoint a pole
ELSE
lon=mod(lon1-asin(sin(tc)*sin(d)/cos(lat))+pi,2*pi)-pi
ENDIF
And this is my C# translation.
// Extend a Point North/South by the specified distance
public static Point ExtendPoint(Point _pt, int _distance, int _bearing )
{
Decimal lat = 0.0;
Decimal lng = 0.0;
lat = Math.Asin(Math.Sin(_pt.Lat) * Math.Cos(_distance) + Math.Cos(_pt.Lat) *
Math.Sin(_distance) * Math.Cos(_bearing));
if (Math.Cos(lat) == 0)
{
lng = _pt.Lng; // endpoint a pole
}
else
{
lng = (
(_pt.Lng - Math.Asin(Math.Sin(_bearing) * Math.Sin(_distance) / Math.Cos(lat))
+ Math.PI) % (2 * Math.PI)) - Math.PI;
}
ret = new Point(lat,lng);
return ret;
}
I am calling this function with a bearing of 0 to calculate the new northerly position and a value of 180 to calculate the new southerly position.
Can anyone either see what I have done wrong or perhaps provide a known working algorithm?
I have a very similar piece of code. It got me very close results when compared to another implementation.
I think the problem with yours is that you are using "distance" as linear distance in meters instead of angular distance in radians.
/// <summary>
/// Calculates the end-point from a given source at a given range (meters) and bearing (degrees).
/// This methods uses simple geometry equations to calculate the end-point.
/// </summary>
/// <param name="source">Point of origin</param>
/// <param name="range">Range in meters</param>
/// <param name="bearing">Bearing in degrees</param>
/// <returns>End-point from the source given the desired range and bearing.</returns>
public static LatLonAlt CalculateDerivedPosition(LatLonAlt source, double range, double bearing)
{
double latA = source.Latitude * UnitConstants.DegreesToRadians;
double lonA = source.Longitude * UnitConstants.DegreesToRadians;
double angularDistance = range / GeospatialConstants.EarthRadius;
double trueCourse = bearing * UnitConstants.DegreesToRadians;
double lat = Math.Asin(
Math.Sin(latA) * Math.Cos(angularDistance) +
Math.Cos(latA) * Math.Sin(angularDistance) * Math.Cos(trueCourse));
double dlon = Math.Atan2(
Math.Sin(trueCourse) * Math.Sin(angularDistance) * Math.Cos(latA),
Math.Cos(angularDistance) - Math.Sin(latA) * Math.Sin(lat));
double lon = ((lonA + dlon + Math.PI) % UnitConstants.TwoPi) - Math.PI;
return new LatLonAlt(
lat * UnitConstants.RadiansToDegrees,
lon * UnitConstants.RadiansToDegrees,
source.Altitude);
}
Where
public const double EarthRadius = 6378137.0; // WGS-84 ellipsoid parameters
and LatLonAlt is in degrees/meters (conversion takes place internally).
Adjust as needed.
I assume you can figure out what the value for UnitConstants.DegreesToRadians is :)
For lazy people, (like me ;) ) a copy-paste solution, Erich Mirabal's version with very minor changes:
using System.Device.Location; // add reference to System.Device.dll
public static class GeoUtils
{
/// <summary>
/// Calculates the end-point from a given source at a given range (meters) and bearing (degrees).
/// This methods uses simple geometry equations to calculate the end-point.
/// </summary>
/// <param name="source">Point of origin</param>
/// <param name="range">Range in meters</param>
/// <param name="bearing">Bearing in degrees</param>
/// <returns>End-point from the source given the desired range and bearing.</returns>
public static GeoCoordinate CalculateDerivedPosition(this GeoCoordinate source, double range, double bearing)
{
var latA = source.Latitude * DegreesToRadians;
var lonA = source.Longitude * DegreesToRadians;
var angularDistance = range / EarthRadius;
var trueCourse = bearing * DegreesToRadians;
var lat = Math.Asin(
Math.Sin(latA) * Math.Cos(angularDistance) +
Math.Cos(latA) * Math.Sin(angularDistance) * Math.Cos(trueCourse));
var dlon = Math.Atan2(
Math.Sin(trueCourse) * Math.Sin(angularDistance) * Math.Cos(latA),
Math.Cos(angularDistance) - Math.Sin(latA) * Math.Sin(lat));
var lon = ((lonA + dlon + Math.PI) % (Math.PI*2)) - Math.PI;
return new GeoCoordinate(
lat * RadiansToDegrees,
lon * RadiansToDegrees,
source.Altitude);
}
private const double DegreesToRadians = Math.PI/180.0;
private const double RadiansToDegrees = 180.0/ Math.PI;
private const double EarthRadius = 6378137.0;
}
Usage:
[TestClass]
public class CalculateDerivedPositionUnitTest
{
[TestMethod]
public void OneDegreeSquareAtEquator()
{
var center = new GeoCoordinate(0, 0);
var radius = 111320;
var southBound = center.CalculateDerivedPosition(radius, -180);
var westBound = center.CalculateDerivedPosition(radius, -90);
var eastBound = center.CalculateDerivedPosition(radius, 90);
var northBound = center.CalculateDerivedPosition(radius, 0);
Console.Write($"leftBottom: {southBound.Latitude} , {westBound.Longitude} rightTop: {northBound.Latitude} , {eastBound.Longitude}");
}
}
I'm not sure if I'm missing something here, but I think the question could be rephrased as, "I have a lat/lon point, and I want to find the point x meters north and x meters south of that point."
If that's the question then you don't need to find a new longitude (which makes things simpler), you just need a new latitude. A degree of latitude is roughly 60 nautical miles long anywhere on Earth, and a nautical mile is 1,852 meters. So, for new latitudes x meters north and south:
north_lat = lat + x / (1852 * 60)
north_lat = min(north_lat, 90)
south_lat = lat - x / (1852 * 60)
south_lat = max(south_lat, -90)
This is not completely accurate because the Earth is not a perfect sphere with exactly 60 nautical miles between each degree of latitude. However, the other answers assume that lines of latitude are equidistant, so I'm assuming you don't care about that. If you're interested in how much error that might introduce, there is a nice table on Wikipedia that shows "Surface distance per 1° change in latitude" for different latitudes at this link:
http://en.wikipedia.org/wiki/Latitude#Degree_length
If you have a given latitude and longitude you can calculate the correct latitude and longitude of an x-km change in latitude like so:
new-lat = ((old-km-north + x-km-change)/40,075) * 360)
^ is the ratio of the ^ times the ratio of the circle
earth the change by 360 to get the total ratio
covers. covered in degrees.
The same can apply to longitude. If you have the total distance plus the change you can calculate the total degrees in a similar fashion.
new-long = ((old-km-east + x-km-change)/40,075) * 360)
^ is the ratio of the ^ times the ratio of the circle
earth the change by 360 to get the total ratio
covers. covered in degrees.
Again, these calculations should work, but I'm running off pure intuition here, but the logic does seem to hold true.
Edit: As pointed out by Skizz 40,075 needs to be adjusted to the circumference of the earth at any given latitude using 2.pi.r.cos(lat) or 40074.cos(lat)
There are problems with the two equations on Ed William's rather awesome site... but I didn't analyze them to see why.
A third equation that I found here seems to give proper results.
Here is the test case in php... the third equation is correct, the first two give wildly incorrect values for longitude.
<?php
$lon1 = -108.553412; $lat1 = 35.467155; $linDistance = .5; $bearing = 170;
$lon1 = deg2rad($lon1); $lat1 = deg2rad($lat1);
$distance = $linDistance/6371; // convert dist to angular distance in radians
$bearing = deg2rad($bearing);
echo "lon1: " . rad2deg($lon1) . " lat1: " . rad2deg($lat1) . "<br>\n";
// doesn't work
$lat2 = asin(sin($lat1) * cos($distance) + cos($lat1) * sin($distance) * cos($bearing) );
$dlon = atan2(sin($bearing) * sin($distance) * cos($lat1), cos($distance) - sin($lat1) * sin($lat2));
$lon2 = (($lon1 - $dlon + M_PI) % (2 * M_PI)) - M_PI; // normalise to -180...+180
echo "lon2: " . rad2deg($lon2) . " lat2: " . rad2deg($lat2) . "<br>\n";
// same results as above
$lat3 = asin( (sin($lat1) * cos($distance)) + (cos($lat1) * sin($distance) * cos($bearing)));
$lon3 = (($lon1 - (asin(sin($bearing) * sin($distance) / cos($lat3))) + M_PI) % (2 * M_PI)) - M_PI;
echo "lon3: " . rad2deg($lon3) . " lat3: " . rad2deg($lat3) . "<br>\n";
// gives correct answer... go figure
$lat4 = asin(sin($lat1) * cos($linDistance/6371) + cos($lat1) * sin($linDistance/6371) * cos($bearing) );
$lon4 = $lon1 + atan2( (sin($bearing) * sin($linDistance/6371) * cos($lat1) ), (cos($linDistance/6371) - sin($lat1) * sin($lat2)));
echo "lon4: " . rad2deg($lon4) . " lat4: " . rad2deg($lat4) . "<br>\n";
?>
Note I recieved by email from the author (Ed Williams) of the first two equations:
From my "implementation notes":
Note on the mod function. This appears to be implemented differently in
different languages, with differing conventions on whether the sign of the
result follows the sign of the divisor or the dividend. (We want the sign
to follow the divisor or be Euclidean. C's fmod and Java's % do not work.)
In this document, Mod(y,x) is the remainder on dividing y by x and always
lies in the range 0 <= mod < x. For instance: mod(2.3,2.)=0.3 and
mod(-2.3,2.)=1.7
If you have a floor function (int in Excel), that returns floor(x)=
"largest integer less than or equal to x" e.g. floor(-2.3)=-3 and
floor(2.3) =2
mod(y,x) = y - x*floor(y/x)
The following should work in the absence of a floor function- regardless of
whether "int" truncates or rounds downward:
mod=y - x * int(y/x)
if ( mod < 0) mod = mod + x
php is like fmod in C and does it "wrong" for my purposes.
It is more accurate if you first reproject it to UTM and then check the distance.
Hope this helps
For people who want a java version Eirch's code
/**
* move latlng point by rang and bearing
*
* #param latLng point
* #param range range in meters
* #param bearing bearing in degrees
* #return new LatLng
*/
public static LatLng moveLatLng(LatLng latLng, double range, double bearing) {
double EarthRadius = 6378137.0;
double DegreesToRadians = Math.PI / 180.0;
double RadiansToDegrees = 180.0 / Math.PI;
final double latA = latLng.latitude * DegreesToRadians;
final double lonA = latLng.longitude * DegreesToRadians;
final double angularDistance = range / EarthRadius;
final double trueCourse = bearing * DegreesToRadians;
final double lat = Math.asin(
Math.sin(latA) * Math.cos(angularDistance) +
Math.cos(latA) * Math.sin(angularDistance) * Math.cos(trueCourse));
final double dlon = Math.atan2(
Math.sin(trueCourse) * Math.sin(angularDistance) * Math.cos(latA),
Math.cos(angularDistance) - Math.sin(latA) * Math.sin(lat));
final double lon = ((lonA + dlon + Math.PI) % (Math.PI * 2)) - Math.PI;
return new LatLng(lat * RadiansToDegrees, lon * RadiansToDegrees);
}

Categories

Resources