I'm searching for an algorithm to convert Lambet72 coordinates to lat/long.
So for example Lambert72 coordinates 148990,169450 must be converted into 50.83546802746704, 4.354415218851164 but most of the algorithm have a little offset (see attachments).
Image 1
Image 2
This is one of the algorithms I found which is close, but still have an error.
Someone has got a better algorithm?
static void Lambert72ToLatLong(double x, double y, ref double longitude, ref double latitude)
{
const double n = 0.77164219;
const double F = 1.81329763;
const double thetaFudge = 0.00014204;
const double e = 0.08199189;
const double a = 6378388;
const double xDiff = 150000;
const double yDiff = 5400088.44;
const double theta0 = 0.07604294;
double xReal = xDiff-x;
double yReal = yDiff-y;
double rho = Math.Sqrt(xReal*xReal + yReal * yReal);
double theta = Math.Atan(xReal/-yReal);
longitude = (theta0 + (theta + thetaFudge) / n) * 180 / Math.PI;
latitude = 0;
for(int i=0; i<10; ++i)
{
latitude = (2 * Math.Atan(Math.Pow(F * a / rho, 1 / n) * Math.Pow((1 + e * Math.Sin(latitude)) / (1 - e * Math.Sin(latitude)), e / 2))) - Math.PI / 2;
}
latitude *= 180 / Math.PI;
}
It seems you are trying to convert Lambert72 (Belgium Dattum 72 LCC 3p) to
WGS84 GPS coordinates. Thus, after converting to spherical latitude and
longitude coordinates, an additional step has to be performed to end up
with the WGS84 coordinates. Here is an alternative code in C# with the full conversion
of Lambert72 to WGS74 which complies with the required decimal accurary, as
you easily can verify for the coordinates presented in your quoted images.
static void Lambert72toWGS84latlong(double X, double Y)
{
double LongRef = 0.076042943; //
double nLamb = 0.7716421928;
double aCarre = Math.Pow(6378388.0,2.0);
double bLamb = 6378388.0 * (1.0 - (1.0 / 297.0));
double eCarre = (aCarre - Math.Pow(bLamb, 2.0)) / aCarre;
double KLamb = 11565915.812935;
double eLamb = Math.Sqrt(eCarre);
double eSur2 = eLamb / 2.0;
double Tan1 = (X - 150000.012) / (5400088.437 - Y);
double Lambda = LongRef + (1.0 / nLamb) * (0.000142043 + Math.Atan(Tan1));
double RLamb = Math.Sqrt(Math.Pow((X - 150000.012) , 2.0) + Math.Pow ((5400088.437 - Y) ,2.0));
double TanZDemi = Math.Pow((RLamb / KLamb),(1.0 / nLamb));
double Lati1 = 2.0 * Math.Atan(TanZDemi);
double eSin;
double Mult1, Mult2, Mult;
double LatiN, Diff;
double lat, lng ;
int i=0;
do
{
eSin = eLamb * Math.Sin(Lati1);
Mult1 = 1.0 - eSin;
Mult2 = 1.0 + eSin;
Mult = Math.Pow((Mult1 / Mult2) , (eLamb / 2.0));
LatiN = (Math.PI / 2.0) - (2.0 * (Math.Atan(TanZDemi * Mult)));
Diff = LatiN - Lati1;
Lati1 = LatiN;
i++;
} while (Math.Abs(Diff)> 0.0000000277777);
lat=LatiN;
lng=Lambda;
double SinLat = Math.Sin(lat);
double SinLng = Math.Sin(lng);
double CoSinLat = Math.Cos(lat);
double CoSinLng = Math.Cos(lng);
double dx = -125.8;
double dy = 79.9;
double dz = -100.5;
double da = -251.0;
double df = -0.000014192702;
double LWf = 1.0 / 297.0;
double LWa = 6378388.0;
double LWb = (1 - LWf) * LWa;
double LWe2 = (2.0 * LWf) - (LWf * LWf);
double Adb = 1.0 / (1.0 - LWf);
double Rn = LWa / Math.Sqrt(1.0 - LWe2 * SinLat * SinLat);
double Rm = LWa * (1 - LWe2) /Math.Pow((1.0 - LWe2 * lat * lat) ,1.5);
double DLat = -dx * SinLat * CoSinLng - dy * SinLat * SinLng + dz * CoSinLat;
DLat = DLat + da * (Rn * LWe2 * SinLat * CoSinLat) / LWa;
DLat = DLat + df * (Rm * Adb + Rn / Adb) * SinLat * CoSinLat;
DLat = DLat / (Rm + 0.0);
double DLng = (-dx * SinLng + dy * CoSinLng) / ((Rn + 0.0) * CoSinLat);
double Dh = dx * CoSinLat * CoSinLng + dy * CoSinLat * SinLng + dz * SinLat;
Dh = Dh - da * LWa / Rn + df * Rn * lat * lat / Adb;
double LatWGS84 = ((lat + DLat) * 180.0) / Math.PI;
double LngWGS84 = ((lng + DLng) * 180.0) / Math.PI;
MessageBox.Show("WGS84-Latitude=" + LatWGS84.ToString("###.######") +
"--WGS84 Longitude=" + LngWGS84.ToString("###.######"));
}
Hope these are helpful.
You have to correct the values for
xDiff
and
yDiff
The correct values should be
xDiff=149910;
yDiff=5400150;
You have also to correct the
i<10
to become
i<5
inside the for-loop for the calculation of the latitude. Then you will get the desired results.
Hope these help!
Related
I'm creating a distance calculator in c# using the haversine equation to calculate the distance between longitudes and latitudes but it is giving the wrong output can anyone see why?
the first long and lat values are for a place in Wales (Bangor) and the other is for a place in England (Manchester)
Here is the code:
using System;
public static class Program
{
static double toRadians(double angle)
{
return (angle * Math.PI) / 180;
}
static double CalcDistance(double lon1, double lon2, double lat1, double lat2)
{
lon1 = toRadians(lon1);
lon2 = toRadians(lon2);
lat1 = toRadians(lat1);
lat2 = toRadians(lat2);
//haversine formula
double dlat, dlon;
dlat = lat2 - lat1;
dlon = lon2 - lon1;
double a = Math.Pow(Math.Sin(dlat / 2), 2) *
Math.Cos(lat1) * Math.Cos(lat2) *
Math.Pow(Math.Sin(dlon / 2), 2);
double c = 2 * Math.Asin(Math.Sqrt(a));
// earths radius is KM, use 3956 for miles
double earthRadius = 6371;
return (c * earthRadius);
}
static void Main(String[] args)
{
double lat1, lat2, lon1, lon2;
lon1= 53.222469;
lat1 = -4.129424;
lon2 = 53.244697;
lat2 = -2.13195;
Console.WriteLine(CalcDistance(lon1, lon2, lat1, lat2) + " KM");
}
}
The output given is 0.04301075336978381 KM when the output should be roughly 130KM
The error is a * vs + (the first one in CalcDistance), but here's a direct conversion from https://www.movable-type.co.uk/scripts/latlong.html, for reference (also adding this to the static double toRadians(this double angle) so it works as an extension method):
static double CalcDistance(double lon1, double lon2, double lat1, double lat2)
{
const double R = 6371;
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;
return d;
}
Let's say I have 2 coordinates that are ~222.33 meters away from each other :
A: 49.25818, -123.20626
B: 49.25813, -123.2032
Those 2 points makes a segment.
How can I calculate the coordinate of point Z that is X meters away from either A or B but towards the other point?
I already know the distance between my 2 points using System.Device.Location library.
GeoCoordinate A = new GeoCoordinate(49.25818, -123.20626);
GeoCoordinate B = new GeoCoordinate(49.25813, -123.2032);
var distanceInMeters = A.GetDistanceTo(B);
// distanceInMeters = 222.33039783713738
I'm looking for something like this:
GeoCoordinate GetPointTowards(GeoCoordinate fromPoint, GeoCoordinate towardPoint, double distanceInMeter) {
[???]
}
I think I may need the bearing or something to be able to get the new point location.
Most examples I've found are for iOS, Android or GMaps with specific libraries..
Here's an outline of how I would do it. With this approach, there is no need to explicitly deal with the difference in units between coordinates and distances because taking the ratio of target to total distance eliminates the unit.
totalDistance = distance in meters between point A and point B.
targetDistance = distance in meters to travel from point A to point B
ratio = targetDistance / totalDistance
diffX = B.X - A.X
diffY = B.Y - A.Y
targetX = A.X + (ratio * diffX)
targetY = A.Y + (ratio * diffY)
But this wouldn't handle the edge cases like being at 179 degrees longitude and adding 3 degrees which would put you at -178 longitude.
This is my code converted to C# from http://www.movable-type.co.uk/scripts/latlong.html. The fraction is from 0 to 1 and is the fraction along the distance from the first point to the second point the output position will be. You could always modify it to take a straight distance value.
public static (double Lat, double Lon) IntermediatePoint((double Lat, double Lon) StartPoint, (double Lat, double Lon) EndPoint, double fraction)
{
if (fraction < 0 || fraction > 1)
throw new ArgumentOutOfRangeException();
double angDist = Distance(StartPoint, EndPoint) / radius;
double lat1 = StartPoint.Lat * (Math.PI / 180);
double lon1 = StartPoint.Lon * (Math.PI / 180);
double lat2 = EndPoint.Lat * (Math.PI / 180);
double lon2 = EndPoint.Lon * (Math.PI / 180);
double a = Math.Sin((1 - fraction) * angDist) / Math.Sin(angDist);
double b = Math.Sin(fraction * angDist) / Math.Sin(angDist);
double x = a * Math.Cos(lat1) * Math.Cos(lon1) + b * Math.Cos(lat2) * Math.Cos(lon2);
double y = a * Math.Cos(lat1) * Math.Sin(lon1) + b * Math.Cos(lat2) * Math.Sin(lon2);
double z = a * Math.Sin(lat1) + b * Math.Sin(lat2);
double lat3 = Math.Atan2(z, Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2)));
double lon3 = Math.Atan2(y, x);
return (lat3 * (180 / Math.PI), lon3 * (180 / Math.PI));
}
public static double Distance((double Lat, double Lon) point1, (double Lat, double Lon) point2)
{
double φ1 = point1.Lat * (Math.PI / 180.0);
double φ2 = point2.Lat * (Math.PI / 180.0);
double Δφ = (point2.Lat - point1.Lat) * (Math.PI / 180.0);
double Δλ = (point2.Lon - point1.Lon) * (Math.PI / 180.0);
double a = Math.Sin(Δφ / 2) * Math.Sin(Δφ / 2) + Math.Cos(φ1) * Math.Cos(φ2) * Math.Sin(Δλ / 2) * Math.Sin(Δλ / 2);
double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
return radius * c;
}
radius is a constant representing the Earth's radius in meters.
i used this code which takes longitude and latitude of two different location and calculates the distance between them
my code is
protected void Button1_Click(object sender, EventArgs e)
{
double lat1= Convert.ToDouble(TextBox1.Text);
double lon1= Convert.ToDouble(TextBox2.Text);
double lat2= Convert.ToDouble(TextBox3.Text);
double lon2= Convert.ToDouble(TextBox4.Text);
var rlat1 = Math.PI * lat1/180;
var rlat2 = Math.PI * lat2/180;
var rlon1 = Math.PI * lon1/180;
var rlon2 = Math.PI * lon2 / 180;
var theta = lon1-lon2;
var rtheta = Math.PI * theta/180;
var dist = Math.Sign(rlat1) * Math.Sign(rlat2) + Math.Cos(rlat1) * Math.Cos(rlat2) * Math.Cos(rtheta);
dist = Math.Acos(dist);
dist = dist * 180/Math.PI;
dist = dist * 60 * 1.1515;
dist = dist * 1.609344 ;
TextBox5.Text = dist.ToString("0.######");
}
but for all the input values the result i am getting is NaN.please help me.
Ok, because I led you up the garden path with my previous answer, I ported this to give you an algorithm that works:
void Main()
{
double lat1=12.916933d,
lon1=77.562658d,
lat2=12.930140d,
lon2=77.587732d;
double dist = GetDistanceFromLatLonInKm(lat1, lon1, lat2, lon2);
// dist == 3.08890370651166 yay!
}
double GetDistanceFromLatLonInKm(double lat1,
double lon1,
double lat2,
double lon2) {
var R = 6371d; // Radius of the earth in km
var dLat = Deg2Rad(lat2 - lat1); // deg2rad below
var dLon = Deg2Rad(lon2 - lon1);
var a =
Math.Sin(dLat / 2d) * Math.Sin(dLat / 2d) +
Math.Cos(Deg2Rad(lat1)) * Math.Cos(Deg2Rad(lat2)) *
Math.Sin(dLon / 2d) * Math.Sin(dLon / 2d);
var c = 2d * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1d - a));
var d = R * c; // Distance in km
return d;
}
double Deg2Rad(double deg) {
return deg * (Math.PI / 180d);
}
Your calculation appears to work correctly when you supply fixed values:
var lat1 = 0d;
var lon1 = 52d;
var lat2 = 0d;
var lon2 = -52d;
which rather implies that these conversions are failing:
double lat1 = Convert.ToDouble(TextBox1.Text);
double lon1 = Convert.ToDouble(TextBox2.Text);
double lat2 = Convert.ToDouble(TextBox3.Text);
double lon2 = Convert.ToDouble(TextBox4.Text);
If you're still having trouble, place a breakpoint on these lines and take a look at the values of TextBox1.Text etc.
For more predictable parsing of floating point numbers, it's best to supply culture information:
Convert.ToDouble("1.2", System.Globalization.CultureInfo.InvariantCulture)
Check if decimal delimiter is valid. It has to be comma or dot, depending on your regional settings.
I am using the following function.
private static Location CoordinateAtADistance(double latOrigin, double lonOrigin, double radius, double angle)
{
double lonDestination;
double R = 6371.0;
double d = radius / R; // d = angular distance covered on earth's surface
double lat1 = ToRadian(latOrigin);
double lon1 = ToRadian(lonOrigin);
double brng = ToRadian(angle);
double latDestination = lat1 + d * Math.Cos(brng);
double dLat = d * Math.Cos(brng);
double dPhi = Math.Log(Math.Tan(latDestination / 2 + Math.PI / 4) / Math.Tan(lat1 / 2 + Math.PI / 4));
double q = (double.IsNaN(dLat / dPhi)) ? dLat / dPhi : Math.Cos(lat1); // E-W line gives dPhi=0
double dLon = d * Math.Sin(brng) / q;
// check for some daft bugger going past the pole
if (Math.Abs(latDestination) > Math.PI / 2)
latDestination = latDestination > 0 ? Math.PI - latDestination : -(Math.PI - latDestination);
lonDestination = (lon1 + dLon +3* Math.PI) % (2 * Math.PI) - Math.PI;
Location nextPoint = new Location();
if (angle == 0)
{
nextPoint.Latitude = ToDegree(latDestination);
nextPoint.Longitude = lonOrigin;
}
if (angle == 90)
{
nextPoint.Latitude = latOrigin;
nextPoint.Longitude = ToDegree(lonDestination);
}
return nextPoint;
}
Here radius is the distance.
Now the problem is when I calculate short distances e.g. a few hundreds kilometers it works perfectly. But for large distances say 11,000 kilometers it gives in correct longitude.
Please not I only move either along latitude or longitude so one of them will not change in any case. While moving for latitude I get correct answer but for longitude values are not even closer.
Please post comments if any thing is unclear.
double latDestination = lat1 + d * Math.Cos(brng);
double dLat = d * Math.Cos(brng);
double dPhi = Math.Log(Math.Tan(latDestination / 2 + Math.PI / 4) / Math.Tan(lat1 / 2 + Math.PI / 4));
double q = (double.IsNaN(dLat / dPhi)) ? dLat / dPhi : Math.Cos(lat1); // E-W line gives dPhi=0
double dLon = d * Math.Sin(brng) / q;
// check for some daft bugger going past the pole
if (Math.Abs(latDestination) > Math.PI / 2)
latDestination = latDestination > 0 ? Math.PI - latDestination : -(Math.PI - latDestination);
lonDestination = (lon1 + dLon + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
A little correction was needed and the above formula works fine.
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()