Calculate future latitude longitude with initial coordinates, heading and distance - c#

I have been reading through stackoverflow and this site (http://www.movable-type.co.uk/scripts/latlong.html) about how to do this, but I cant get my code to give a correct answer. It is giving a coordinate that isnt in the correct direction. I have been working on this all day and seem to have hit a wall. This is my function:
public static void destination()
{
double heading = 335.9;
double startLatitude = 41.8369;
double startLongitude = 87.6847;
//Convert to Radians
startLatitude = startLatitude * Math.PI / 180;
startLongitude = startLongitude * Math.PI / 180;
heading = heading * Math.PI / 180;
int distanceKilometers = 100;
double angularDistance = distanceKilometers / 6371e3;
double endLat = Math.Asin((Math.Sin(startLatitude) * Math.Cos(angularDistance)) +
(Math.Cos(startLatitude) * Math.Sin(angularDistance) * Math.Cos(heading)));
double endLong = startLongitude + (Math.Atan2((Math.Sin(heading) * Math.Sin(angularDistance) * Math.Cos(startLatitude)),
Math.Cos((angularDistance) - (Math.Sin(startLatitude) * Math.Sin(endLat)))));
endLong = (endLong + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
Console.WriteLine("endLatitude: " + (endLat * 180 / Math.PI) + " endLongitude: " + (endLong * 180 / Math.PI));
}

I use the below function.
float provide you a 3 meters precision. If you need more, use double.
internal class SxMath
{
internal const float PI = (float)Math.PI;
internal const float x2PI = PI * 2;
internal const float PIDiv2 = PI/2;
internal const float RadPerSec = (float)(PI / 648000F);
internal const float SecPerRad = (float)(648000F / PI);
internal const float RadPerDeg = PI / 180;
internal const float RadPerMin = PI / 10800;
internal const float DegPerRad = 180 / PI;
internal const float MinParRad = (float)(10800.0/PI);
internal const float RadPerMeter = RadPerMin * (1F/1852F) /* Meter_To_NMs */ ;
internal static float RealMod(float val,float modval)
{ // Example : RealMod(3,2*PI)=3 , RealMod(2*PI+3,2*PI)=3 , RealMod(-3,2*PI)=2*PI-3
float result = (float)Math.IEEERemainder(val,modval);
if (result<0) result = result + modval;
return result;
}
} // SxMath
internal struct SxGeoPt
{
internal float lat ; // in radians, N positive
internal float lon ; // in radians, W positive
} // SxGeoPt
internal static SxGeoPt GEO_CoorPointInAzim(SxGeoPt p1,float az,float raddist)
// This procedure provides coordinates of the point p2 located
// - at a distance raddist of a point p1
// - in the direction of azimuth az
// input p1 <SxGeoPt> coordinates of reference point
// raddist <float> distance in radian between p1 and p2
// az <float> azimut of p2 from p1,
// (az=0, if p1 and p2 on same longitude and P2 north of P1)
// (az=90, if p1 is on equator and p2 on equtor at East of P1)
// output p2 <SxGeoPt> coordinates of resulting point
{
SxGeoPt result;
if (p1.lat>SxMath.PIDiv2-SxMath.RadPerMin)
{ if (az<=SxMath.PI) result.lon=az; else result.lon=az-SxMath.PI; result.lat=SxMath.PIDiv2-raddist; }
else if (p1.lat<-SxMath.PIDiv2+SxMath.RadPerMin)
{ if (az<=SxMath.PI) result.lon=-az; else result.lon=-az+SxMath.PI; result.lat=-SxMath.PIDiv2+raddist; }
else
{
result.lat = (float)Math.Asin((Math.Sin(p1.lat)*Math.Cos(raddist)) +
(Math.Cos(p1.lat)*Math.Sin(raddist)*Math.Cos(az)));
float dlon = (float)Math.Atan2( Math.Sin(az)*Math.Sin(raddist)*Math.Cos(p1.lat),
Math.Cos(raddist)-Math.Sin(p1.lat)*Math.Sin(result.lat));
result.lon = SxMath.RealMod(p1.lon-dlon+SxMath.PI,SxMath.x2PI)-SxMath.PI;
}
return result;
}
As I extracted code from different classes, I hope that nothing is missing.
To get the input parameter DistInRad from Kilometers:
float raddist = distanceKilometers * 1000f * SxMath.RadPerMeter ;

Related

Map Coordinates C#

I have a set of latitude Longitude points. If I wanted to test if a new point was within x metres of any of the existing points would this be possible?
Would it be best if I use this way?
ForEach(Coordinate coord in Coordinates)
{
var distance = GeoCoordinate.GetDistance(lat,lon);
if(distance <= x)
{
addToQualifyingList(coord);
}
}
and compare the new coordinate with every point in the set and check to see it is within x metres?
Here is a method to calculate the distance between 2 points (lat1, lon1 and lat2, lon2)
public enum DistanceUnit { miles, kilometers, nauticalmiles }
public double GetDistance( double lat1, double lon1 , double lat2 , double lon2, DistanceUnit unit)
{
Func<double, double> deg2rad = deg => (deg * Math.PI / 180.0);
Func<double, double> rad2deg = rad => (rad / Math.PI * 180.0);
double theta = lon1 - lon2;
double dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(deg2rad(theta));
dist = Math.Acos(dist);
dist = rad2deg(dist);
dist = dist * 60 * 1.1515;
if (unit == DistanceUnit.kilometers)
{
dist = dist * 1.609344;
}
else if (unit == DistanceUnit.nauticalmiles)
{
dist = dist * 0.8684;
}
return (dist);
}
To determine all Coordinates with distance below 1 kilometer:
List<Coordinate> result = Coordinates.Where(x => GeoCoordinate.GetDistance(lat,lon, x.lan, x.lon, DistanceUnit.kilometers) < 1).ToList();
Latitude and Longitude are both needed to know the position on earth or any other sphere shaped object. These are given in degree from their respective zero line / point.
http://www.movable-type.co.uk/scripts/latlong.html
Has a solution in Java
> var R = 6371e3; // metres
> var φ1 = lat1.toRadians();
> var φ2 = lat2.toRadians();
> var Δφ = (lat2-lat1).toRadians();
> var Δλ = (lon2-lon1).toRadians();
>
> var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
> Math.cos(φ1) * Math.cos(φ2) *
> Math.sin(Δλ/2) * Math.sin(Δλ/2);
> var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
>
> var d = R * c;
Apparently, this is this is one of the best solutions for small distances.
You should be able to just copy and paste it to C#, youll jsut have to change the variable names.

How can I see distance between two pins in xamarin forms and get the distance as a string?

I have two pins on the map with long and latitude and I wish to see the distance between them.
This is what I have so far.
var myPin = new Pin ();
myPin.Label = "pin1";
myPin.Address = "test1";
myPin.Position = new Position(37.797513, -122.402068);
myPin.Label = "pin2";
myPin.Address = "test2";
myPin.Position = new Position(37.7, -122.3);
mymap.Pins.Add(myPin);
So two different pins on my map. How can I see the distance between these two in km? My goal is to make a label with the distance (km) as the text.
(I have a customer renderer base ready incase the only way to solve the distancefunction is via a renderer).
if u have two pins you have their longitude and latitude values , so can calculate the distance between em using below code (taken from geodatasource.com)
private double distance(double lat1, double lon1, double lat2, double lon2, char unit) {
double theta = lon1 - lon2;
double dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(deg2rad(theta));
dist = Math.Acos(dist);
dist = rad2deg(dist);
dist = dist * 60 * 1.1515;
if (unit == 'K') {
dist = dist * 1.609344;
} else if (unit == 'N') {
dist = dist * 0.8684;
}
return (dist);
}
private double deg2rad(double deg) {
return (deg * Math.PI / 180.0);
}
private double rad2deg(double rad) {
return (rad / Math.PI * 180.0);
}
so basically you just need one starting reference of lat/long value from where you will take reference for further pin to show this distance as a label
There is one built into the Location class
public static Void DistanceBetween (Double startLatitude, Double startLongitude, Double endLatitude, Double endLongitude, Single[] results)
See this option also using the CoreLocation class
Calculate distance between two positions

Formula for triangulation (3 references + distances)

I am trying to implement a function that will give me the GEO location (Lat,Long) given 3 GEO reference points and radius away from each point.
The signature for the function I'm looking for is:
public static GeoLocation Triangle(GeoLocation pos1, double r1, GeoLocation pos2,
double r2, GeoLocation pos3, double r3)
As example, 3 friends meet up somewhere secret. Each one can only tell me where he/she lives (GeoLocation = lat,long) and how far they are meeting from their house (r = radius). Given 3 such reference points (from all 3 friends), I should have sufficient information to calculate this secret meeting point as a GeoLocation.
This problem is very similar to the mobile / towers problem where you triangulate a mobile by measuring individual signal strengths from a few towers.
I have tried to find formulas online for quite some time now, which is why I'm posting my question here on Stack Overflow.
I will appreciate it if you could help me fill in the formula (Triangle method) - Thanks.
Code I have so far:
public class GeoLocation
{
private double _latitude;
private double _longitude;
public GeoLocation(double latitude, double longitude)
{
this._latitude = latitude;
this._longitude = longitude;
}
//Tested and working!
public double DistanceToKm(GeoLocation loc)
{
double lat1, lon1, lat2, lon2;
lat1 = this._latitude;
lon1 = this._longitude;
lat2 = loc._latitude;
lon2 = loc._longitude;
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2 - lat1); // deg2rad below
var dLon = deg2rad(lon2 - lon1);
var a =
Math.Sin(dLat / 2) * Math.Sin(dLat / 2) +
Math.Cos(deg2rad(lat1))*Math.Cos( deg2rad(lat2))*
Math.Sin(dLon / 2) * Math.Sin(dLon / 2)
;
var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
var d = R*c; // Distance in km
return d;
}
}
Code which I think is not needed, but for what it's worth:
public static Coords ToCoord(GeoLocation pos)
{
var x = Math.Cos(pos._longitude) * Math.Cos(pos._latitude);
var y = Math.Sin( pos._longitude) * Math.Cos(pos._latitude);
var z = Math.Sin(pos._latitude);
return new Coords(x,y,z);
}
class Coords
{
public double x;
public double y;
public double z;
public Coords(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
}
Seems this is the solution after all.
https://gis.stackexchange.com/questions/66/trilateration-using-3-latitude-and-longitude-points-and-3-distances
... far more complicated than school geometry #DrKoch
Here is the Python solution:
yC = earthR *(math.cos(math.radians(LatC)) * math.sin(math.radians(LonC)))
zC = earthR *(math.sin(math.radians(LatC)))
P1 = array([xA, yA, zA])
P2 = array([xB, yB, zB])
P3 = array([xC, yC, zC])
#from wikipedia
#transform to get circle 1 at origin
#transform to get circle 2 on x axis
ex = (P2 - P1)/(numpy.linalg.norm(P2 - P1))
i = dot(ex, P3 - P1)
ey = (P3 - P1 - i*ex)/(numpy.linalg.norm(P3 - P1 - i*ex))
ez = numpy.cross(ex,ey)
d = numpy.linalg.norm(P2 - P1)
j = dot(ey, P3 - P1)
#from wikipedia
#plug and chug using above values
x = (pow(DistA,2) - pow(DistB,2) + pow(d,2))/(2*d)
y = ((pow(DistA,2) - pow(DistC,2) + pow(i,2) + pow(j,2))/(2*j)) - ((i/j)*x)
# only one case shown here
z = sqrt(pow(DistA,2) - pow(x,2) - pow(y,2))
#triPt is an array with ECEF x,y,z of trilateration point
triPt = P1 + x*ex + y*ey + z*ez
#convert back to lat/long from ECEF
#convert to degrees
lat = math.degrees(math.asin(triPt[2] / earthR))
lon = math.degrees(math.atan2(triPt[1],triPt[0]))
print lat, lon`

How do I draw a circle on my Bing Map application around a centerpoint with a radius given in miles

I have been able to draw an ellipse on my map using latitude and longitude values around a given center point. Although I see a shape on the map, I get an ellipse instead of a circle and I don't think it matches the distance specified. I intend to use this to display objects within that circle (this will be done later on once I can get the circle displaying properly, which is the reason why i need a circle not an ellipse as it should be perfectly round).
I am using a Bing Maps API. I wish to draw the circle in a given miles (distance) from the center which has been passed in through the parameter, the other variable in the parameter called miles is just holding a double value of 1D. I think the problem is to do with the way my maths is being calculated. Has anyone got a clue on how I can refine this code to calculate my miles better.
private void drawPoly(SearchLocation center, Double miles)
{
//amount of vertex
double vertexCount = 100D;
//used by the api to carried out searches
List<SearchLocation> vertices = new List<SearchLocation>();
double v = 0;
double radians = Math.PI / 180D;
double radiansPerDegree = Math.PI / 180D;
double degreePerVertex = 360D / vertexCount;
double radiansPerVertex = degreePerVertex * radiansPerDegree;
var centerOfMap = center;
const double degLatMiles = 68.68637156368D;
double degLonMiles = Math.Cos(center.Latitude.Value) * (68.68637156368D);
double milesLat = (miles * degLatMiles) / 3600;
double milesLon = (miles * degLonMiles) / 3600;
for (v = 0; v < vertexCount; v++)
{
radians = v * radiansPerVertex;
//adds the miles from the center point and draws a circle
double centrLat = center.Latitude.Value + (milesLat * Math.Sin(radians));
double centrLon = center.Longitude.Value + (milesLon * Math.Cos(radians));
vertices.Add(new SearchLocation() { Latitude = centrLat, Longitude = centrLon });
}
Ok, I've misundestood your question. This should work :
/// <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 PointLatLng CalculateDerivedPosition(PointLatLng source, double range, double bearing)
{
double latA = source.Lat * DEGREES_TO_RADIANS;
double lonA = source.Lng * DEGREES_TO_RADIANS;
double angularDistance = range / EARTH_RADIUS_M;
double trueCourse = bearing * DEGREES_TO_RADIANS;
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) % (Math.PI * 2)) - Math.PI;
return new PointLatLng(
lat / DEGREES_TO_RADIANS,
lon / DEGREES_TO_RADIANS);
}
Juste take your center as source :
for (int i = 0; i < 360; i++)
{
vertices.Add(CalculateDerivedPosition(center, circleRadius, i));
}
To prevent elipses on sertain latitudes I use the following code:
// Function to draw circle on map:
private void DrawCircle(BasicGeoposition CenterPosition, int Radius)
{
Color FillColor = Colors.Purple;
Color StrokeColor = Colors.Red;
FillColor.A = 80;
StrokeColor.A = 80;
Circle = new MapPolygon
{
StrokeThickness = 2,
FillColor = FillColor,
StrokeColor = StrokeColor,
Path = new Geopath(Functions.CalculateCircle(CenterPosition, Radius))
};
mpBingMaps.MapElements.Add(Circle);
}
// Constants and helper functions:
const double earthRadius = 6371000D;
const double Circumference = 2D * Math.PI * earthRadius;
public static List<BasicGeoposition> CalculateCircle(BasicGeoposition Position, double Radius)
{
List<BasicGeoposition> GeoPositions = new List<BasicGeoposition>();
for (int i = 0; i <= 360; i++)
{
double Bearing = ToRad(i);
double CircumferenceLatitudeCorrected = 2D * Math.PI * Math.Cos(ToRad(Position.Latitude)) * earthRadius;
double lat1 = Circumference / 360D * Position.Latitude;
double lon1 = CircumferenceLatitudeCorrected / 360D * Position.Longitude;
double lat2 = lat1 + Math.Sin(Bearing) * Radius;
double lon2 = lon1 + Math.Cos(Bearing) * Radius;
BasicGeoposition NewBasicPosition = new BasicGeoposition();
NewBasicPosition.Latitude = lat2 / (Circumference / 360D);
NewBasicPosition.Longitude = lon2 / (CircumferenceLatitudeCorrected / 360D);
GeoPositions.Add(NewBasicPosition);
}
return GeoPositions;
}
private static double ToRad(double degrees)
{
return degrees * (Math.PI / 180D);
}
This code is usefull for small radius of less than a few miles.

How can I determine the distance between two sets of latitude/longitude coordinates?

I am trying to write something that will determine the distance between to sets of lat/lon coordinates.
I am using the following code which I found on this site:
public static double distance (double lat1, double lon1, double lat2, double lon2) {
double lat1 = Convert.ToDouble(latitude);
double lon1 = Convert.ToDouble(longitude);
double lat2 = Convert.ToDouble(destlat);
double lon2 = Convert.ToDouble(destlon);
double theta = toRadians(lon1-lon2);
lat1 = toRadians(lat1);
lon1 = toRadians(lon1);
lat2 = toRadians(lat2);
lon2 = toRadians(lon2);
double dist = sin(lat1)*sin(lat2) + cos(lat1)*cos(lat2)*cos(theta);
dist = toDegrees(acos(dist)) * 60 * 1.1515 * 1.609344 * 1000;
return dist;
}
My problem is that I am running into the compile error "The name 'toRadians'/'cos'/'sin/'toDegrees' does not exist in the current context..." What am I doing wrong?
You may want to use the following C# class:
public static class GeoCodeCalc
{
public const double EarthRadiusInMiles = 3956.0;
public const double EarthRadiusInKilometers = 6367.0;
public static double ToRadian(double val) { return val * (Math.PI / 180); }
public static double DiffRadian(double val1, double val2) { return ToRadian(val2) - ToRadian(val1); }
public static double CalcDistance(double lat1, double lng1, double lat2, double lng2)
{
return CalcDistance(lat1, lng1, lat2, lng2, GeoCodeCalcMeasurement.Miles);
}
public static double CalcDistance(double lat1, double lng1, double lat2, double lng2, GeoCodeCalcMeasurement m)
{
double radius = GeoCodeCalc.EarthRadiusInMiles;
if (m == GeoCodeCalcMeasurement.Kilometers) { radius = GeoCodeCalc.EarthRadiusInKilometers; }
return radius * 2 * Math.Asin( Math.Min(1, Math.Sqrt( ( Math.Pow(Math.Sin((DiffRadian(lat1, lat2)) / 2.0), 2.0) + Math.Cos(ToRadian(lat1)) * Math.Cos(ToRadian(lat2)) * Math.Pow(Math.Sin((DiffRadian(lng1, lng2)) / 2.0), 2.0) ) ) ) );
}
}
public enum GeoCodeCalcMeasurement : int
{
Miles = 0,
Kilometers = 1
}
Usage:
// Calculate Distance in Miles
GeoCodeCalc.CalcDistance(47.8131545175277, -122.783203125, 42.0982224111897, -87.890625);
// Calculate Distance in Kilometers
GeoCodeCalc.CalcDistance(47.8131545175277, -122.783203125, 42.0982224111897, -87.890625, GeoCodeCalcMeasurement.Kilometers);
Source: Chris Pietschmann - Calculate Distance Between Geocodes in C# and JavaScript
You can write a toRadians function like this:
double ToRadians(double degrees) { return degrees * Math.PI / 180; }
You can write a toDegrees function like this:
double ToDegrees(double radians) { return radians * 180 / Math.PI; }
You should replace sin and cos with Math.Sin and Math.Cos.
This looks like C#.
First you need to define toRadians and toDegrees:
double toRadians(double degrees) {
double sign = Math.Sign(degrees);
while(Math.Abs(degrees) > 360) {
degrees -= sign * 360;
}
return Math.PI * degrees / 180;
}
double toDegrees(double radians) {
double sign = Math.Sign(radians);
while(Math.Abs(radians) > 2 * Math.PI) {
radians -= sign * 2 * Math.PI;
}
return 180 * radians / Math.PI;
}
Then, to use the trigonometric functions you need to use Math.Sin, Math.Cos, etc.
double dist = Math.Sin(lat1) * Math.Sin(lat2)
+ Math.Cos(lat1) * Math.Cos(lat2) * Math.Cos(theta);
and
dist = toDegrees(Math.Acos(dist)) * 60 * 1.1515 * 1.609344 * 1000;
Comments:
public static double distance (double lat1, double lon1, double lat2, double lon2) {
double lat1 = Convert.ToDouble(latitude);
double lon1 = Convert.ToDouble(longitude);
double lat2 = Convert.ToDouble(destlat);
double lon2 = Convert.ToDouble(destlon);
What is this? Where are latitude, longitude, destlat and destlon defined? Further, it appears you have lat1, lon1 lat2 and lon2 as parameters to this method so that you can not define locals here with the same name.
double theta = toRadians(lon1-lon2);
lat1 = toRadians(lat1);
lon1 = toRadians(lon1);
lat2 = toRadians(lat2);
lon2 = toRadians(lon2);
This is bad style. If lat1 represents a latitude in degrees it is far better to compute a radians-equivalent value of lat1 like this:
double lat1Radians = toRadians(lat1);
Thus replace the above with:
double theta = toRadians(lon1-lon2);
double lat1Radians = toRadians(lat1);
double lon1Radians = toRadians(lon1);
double lat2Radians = toRadians(lat2);
double lon2Radians = toRadians(lon2);
Lastly:
double dist = sin(lat1) * sin(lat2)
+ cos(lat1) * cos(lat2) * cos(theta);
dist = toDegrees(acos(dist)) * 60 * 1.1515 * 1.609344 * 1000;
This is bad style too. The first formula and the second formula can not both possibly represent the distance that you are trying to calculate. You should assign the result of the first formula to a variable with a more meaningful name. As a worst case, at least do the following:
double temp = Math.Sin(lat1) * Math.Sin(lat2)
+ Math.Cos(lat1) * Math.Cos(lat2) * Math.Cos(theta);
double dist = toDegrees(Math.Acos(dist)) * 60 * 1.1515 * 1.609344 * 1000;
return dist;
I know this question is really old, but in case anyone else stumbles across this, use GeoCoordinate from System.Device:
var distanceInMeters = new GeoCoordinate(lat1, lon1)
.GetDistanceTo(new GeoCoordinate(lat2, lon2));
Calculating Distance between Latitude and Longitude points...
double Lat1 = Convert.ToDouble(latitude);
double Long1 = Convert.ToDouble(longitude);
double Lat2 = 30.678;
double Long2 = 45.786;
double circumference = 40000.0; // Earth's circumference at the equator in km
double distance = 0.0;
double latitude1Rad = DegreesToRadians(Lat1);
double latititude2Rad = DegreesToRadians(Lat2);
double longitude1Rad = DegreesToRadians(Long1);
double longitude2Rad = DegreesToRadians(Long2);
double logitudeDiff = Math.Abs(longitude1Rad - longitude2Rad);
if (logitudeDiff > Math.PI)
{
logitudeDiff = 2.0 * Math.PI - logitudeDiff;
}
double angleCalculation =
Math.Acos(
Math.Sin(latititude2Rad) * Math.Sin(latitude1Rad) +
Math.Cos(latititude2Rad) * Math.Cos(latitude1Rad) * Math.Cos(logitudeDiff));
distance = circumference * angleCalculation / (2.0 * Math.PI);
return distance;
You're going to need to adapt this code a bit.
As SLaks, says, you will need to define your own toRadians() method because .NET does not have a native version.
You will also need to change the calls to cos() and sin() to be: Math.Cos() and Math.Sin()

Categories