Distance between 2 geocodes - dictionary

What is the formula for calculating the distance between 2 geocodes? I have seen some of the answers on this site but they basically say to rely on SQL Server 08 functions, I'm not on 08 yet. Any help would be appreciated.

Use an approximation of the earth and the Haversine formula. You can get a javascript version on the following url, which you can translate to your language of choice:
http://www.movable-type.co.uk/scripts/latlong.html
Here is another way: http://escience.anu.edu.au/project/04S2/SE/3DVOT/3DVOT/pHatTrack_Application/Source_code/pHatTrack/Converter.java

Take a look here for a SQL server 2000 version SQL Server Zipcode Latitude/Longitude proximity distance search

This will do it for you in c#.
Within the namespace put these:
public enum DistanceType { Miles, Kilometers };
public struct Position
{
public double Latitude;
public double Longitude;
}
class Haversine
{
public double Distance(Position pos1, Position pos2, DistanceType type)
{
double preDlat = pos2.Latitude - pos1.Latitude;
double preDlon = pos2.Longitude - pos1.Longitude;
double R = (type == DistanceType.Miles) ? 3960 : 6371;
double dLat = this.toRadian(preDlat);
double dLon = this.toRadian(preDlon);
double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) +
Math.Cos(this.toRadian(pos1.Latitude)) * Math.Cos(this.toRadian(pos2.Latitude)) *
Math.Sin(dLon / 2) * Math.Sin(dLon / 2);
double c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));
double d = R * c;
return d;
}
private double toRadian(double val)
{
return (Math.PI / 180) * val;
}
Then to utilise these in the main code:
Position pos1 = new Position();
pos1.Latitude = Convert.ToDouble(hotelx.latitude);
pos1.Longitude = Convert.ToDouble(hotelx.longitude);
Position pos2 = new Position();
pos2.Latitude = Convert.ToDouble(lat);
pos2.Longitude = Convert.ToDouble(lng);
Haversine calc = new Haversine();
double result = calc.Distance(pos1, pos2, DistanceType.Miles);

If
you know that the 2 points are "not too far from each other"
and you tolerate a "reasonably small" error.
Then, consider that the earth is flat between the 2 points :
The distance difference in the latitude direction is EarthRadius * latitude difference
The distance difference in the longitude direction is EarthRadius * longitude difference * cos(latitude).
We multiply by cos(lat) because the longitude degrees don't make the same km distance if the latitude changes. As P1 and P2 are close, cos(latP1) is close from cos(latP2)
Then Pythagore
In JavaScript :
function ClosePointsDistance(latP1, lngP1, latP2, lngP2) {
var d2r = Math.PI / 180,
R=6371; // Earth Radius in km
latP1 *= d2r; lngP1 *= d2r; latP2 *= d2r; lngP2 *= d2r; // convert to radians
dlat = latP2 - latP1,
dlng = (lngP2 - lngP1) * Math.cos(latP1);
return R * Math.sqrt( dlat*dlat + dlng*dlng );
}
I tested it between Paris and Orleans (France) : the formula finds 110.9 km whereas the (exact) Haversine formula finds 111.0 km.
!!! Beware of situations around the meridian 0 (you may shift it) : if P1 is at Lng 359 and P2 is at Lng 0, the function will consider them abnormally far !!!

The pythagorean theorem as offered up by others here doesn't work so well.
The best, simple answer is to approximate the earth as a sphere (its actually a slightly flattened sphere, but this is very close). In Haskell, for instance you might use the following, but the math can be transcribed into pretty much anything:
distRadians (lat1,lon1) (lat2,lon2) =
radius_of_earth *
acos (cos lat1 * cos lon1 * cos lat2 * cos lon2 +
cos lat1 * sin lon1 * cos lat2 * sin lon2 +
sin lat1 * sin lat2) where
radius_of_earth = 6378 -- kilometers
distDegrees a b = distRadians (coord2rad a) (coord2rad b) where
deg2rad d = d * pi / 180
coord2rad (lat,lon) = (deg2rad lat, deg2rad lon)
distRadians requires your angles to be given in radians.
distDegrees is a helper function that can take lattitudes and longitudes in degrees.
See this series of posts for more information on the derivation of this formula.
If you really need the extra precision granted by assuming the earth is ellipsoidal, see this FAQ: http://www.movable-type.co.uk/scripts/gis-faq-5.1.html

Here is a way to do it if you are using sql server.
CREATE function dist (#Lat1 varchar(50), #Lng1 varchar(50),#Lat2 varchar(50), #Lng2 varchar(50))
returns float
as
begin
declare #p1 geography
declare #p2 geography
set #p1 = geography::STGeomFromText('POINT('+ #Lng1+' '+ #Lat1 +')', 4326)
set #p2 = geography::STGeomFromText('POINT('+ #Lng2+' '+ #Lat2 +')', 4326)
return #p1.STDistance(#p2)
end

You're looking for the length of the Great Circle Path between two points on a sphere. Try looking up "Great Circle Path" or "Great Circle Distance" on Google.

Sorry, I don't know what country you are in even. Are we talking about Easting and Northings (UK, Ordance Survey system) or Lat/Long or some other system?
If we are talking Easting and Northing then you can use
sqr((x1-x2)^2 + (y1-y2)^2)
This does not allow for the fact that the earth is a sphere, but for short distances you won't notice. We use it at work for distances between points within the county.
Be carful about how longer grid reference you use. I think an 8 figure reference will give you a distance in metres. I'll be able to get a definate answer at work next week if no one else has supplied it.

the pythagorean theorem?

Related

Bearing(azimuth) and distance via 2 gps coordnates (c#)

I'm trying to find the angle to north(bearing/azimuth) & distance between 2 gps coordinates. But obviously I have a mistake somewhere - it gives me wrong bearing&distance values. Please correct me where I'm wrong. Trying it in Unity 5 (c#).
Here is the code:
public float pointX;
public float pointY;
public float lat1=55.500817f;
public float lat2=55.380680f;
public float lon1=37.568342f;
public float lon2=37.822586f;
public float azimuth;
void Update () {
float dlon = lon2 - lon1;
float dlat = lat2 - lat1;
pointX = Mathf.Sin(dlon* 0.01745329f)*Mathf.Cos(lat2* 0.01745329f);
pointY = Mathf.Cos (lat1* 0.01745329f) * Mathf.Sin (lat2* 0.01745329f) - Mathf.Sin (lat1* 0.01745329f) * Mathf.Cos (lat2* 0.01745329f) * Mathf.Cos (dlon*0.01745329f);
azimuth=Mathf.Atan2(pointX, pointY)*57.29578f;
double distance = Math.Pow(Math.Sin(dlat/2*0.01745329),2.0)+(Math.Cos(lat1* 0.01745329)*Math.Cos(lat2* 0.01745329)* Math.Pow(Math.Sin(dlon/2* 0.01745329),2.0));
distance = 2.0*6376500.0*Math.Atan2(Math.Sqrt(distance),Math.Sqrt(1.0-distance));
where * 0.01745329f is the conversion from degrees to radians and *57.29578f is the conversion from radians to degrees
Let's assume all the angles are already converted to radians, and use Re as the Earth's mean radius, and we'll assume a spherical Earth model. There are corrections for the ellipsoidal shape of the Earth but this will get you close. I'll use python-style coding since I know nothing about C#.
#
# North Distance of point 2 from point 1
#
dN = Re * dlat
#
# East Distance of point 2 from point 1
#
dE = Re * dlon * cos(0.5 * (lat1 + lat2))
#
# Distance between points
#
distance=math.sqrt(dN**2 + dE**2)
#
# Azimuth to point 2 from point 1 in radians
#
azimuth=math.atan2(dE,dN)
I copied your code (to java), 1:1
There is no bug in your azimuth code.
Either the cause is by usage of Mathf (float) instead of the double variant
or you just look at the wrong data or wrong output.
As intermediate values I get:
pointx= 0.0025209875920285405,
pointy = -0.0020921620920549278,
azimuth = 129.68

GPS 'Submarine' Radar Detecting Other location

Lets say i have a drone and my phone. I have looked at NORTH, and placed the drone 4 meters in my front. I should look at the radar, and see the drone at the north position.
My radar is 256x256 pixels, and max distance of the drone is 200m witch is aprox 0.002 Lat/Long degrees.
So, ive made a simple test class to test this drone at my north.
public static void main(String[] args) {
BigDecimal droneLat = new BigDecimal(-22.811468333334087077446383773349225521087646484375);
BigDecimal droneLong = new BigDecimal(-47.04746500000123177187560941092669963836669921875);
BigDecimal phoneLat = new BigDecimal(-22.81129370000000022855601855553686618804931640625);
BigDecimal phoneLong = new BigDecimal(-47.04832809999999909678081166930496692657470703125);
BigDecimal latDiff = phoneLat.subtract(droneLat);
BigDecimal longDiff = phoneLong.subtract(droneLong);
int pixelsLat = degreesToPixels265x265(latDiff.abs());
int pixelsLong = degreesToPixels265x265(longDiff.abs());
if (latDiff.compareTo(new BigDecimal(0)) < 0) { // drone > phone means phone is farther to north, phone lat will be lower, it will show lower in radar
pixelsLat = -pixelsLat;
}
if (longDiff.compareTo(new BigDecimal(0)) > 0) { // drone > phone means phone is farther to north, phone lat will be lower, it will show lower in radar
pixelsLong = -pixelsLong;
}
System.out.println("DiffLat "+latDiff);
System.out.println("DiffLong "+longDiff);
System.out.println("Pixels lat = "+pixelsLat);
System.out.println("Pixels long = "+pixelsLong);
}
public static int degreesToPixels265x265(BigDecimal n) {
BigDecimal p1 = n.multiply(new BigDecimal(256/2));
return p1.divide(new BigDecimal(0.002d),2,BigDecimal.ROUND_CEILING).intValue();
}
Pixels Lat will sum to 128 to draw the drones position, so is pixelsLong. As the drone is in my north, should pixels lat be more positive ?
Am i doing some wrong math here to detect the true coordinates to draw this ?
Thanks alot for the attention !
The general problem you're trying to solve is "projection": Projecting a lat/lon coordinate that's on a sphere onto a flat surface (the screen). Here's a question/answer about how to solve that problem: Converting longitude/latitude to X/Y coordinate
But if you don't care about solving the general problem of projection, for any projection (Mercator, etc.) and handling very long distances (thousands of miles) and edge cases (you're flying near the north or south pole), you can do something pretty simple: Compute the bearing and distance from point A (your location) and point B (the drone's location). Using that bearing and distance, plot the drone on the screen with an approximation that should work fine for a few hundred meters.
To compute the distance, use the Haversine formula:
public static double distance(double lat1, double lon1, double lat2, double lon2) {
double R = 6372.8; // Radius of the earth in kilometers.
double dLat = Math.toRadians(lat2 - lat1);
double dLon = Math.toRadians(lon2 - lon1);
lat1 = Math.toRadians(lat1);
lat2 = Math.toRadians(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.asin(Math.sqrt(a));
return R * c;
}
And to compute the angle between two points (really just the initial angle--on a sphere, the angle changes as you get closer but we're approximating over a short distance):
public static double bearing(double lat1, double lon1, double lat2, double lon2) {
double latitude1 = Math.toRadians(lat1);
double latitude2 = Math.toRadians(lat2);
double longitude1 = Math.toRadians(lon1);
double longitude2 = Math.toRadians(lon2);
double longDiff = longitude2 - longitude1;
double y = Math.sin(longDiff) * Math.cos(latitude2);
double x = Math.cos(latitude1) * Math.sin(latitude2) - Math.sin(latitude1) * Math.cos(latitude2) * Math.cos(longDiff);
return Math.atan2(y, x);
}
Once you can compute distance & bearing, you can map that onto your screen (what you're doing is converting polar coordinates to cartesian/XY coordinates):
public static void plotLatLon(double droneLat, double droneLon) {
// Get location from phone geolocation.
double phoneLat = -22.8112937000;
double phoneLon = -47.0483281000;
int width = 256;
int height = 256;
// 256 pixels = 400 meters; 200 meters away = edge of screen.
double scaleFactor = 256.0 / 400.0;
double bearing = bearing(phoneLat, phoneLon, droneLat, droneLon);
double distance = distance(phoneLat, phoneLon, droneLat, droneLon);
System.out.println("Bearing: " + (Math.toDegrees(bearing) + 360.0) % 360.0);
System.out.println("Distance: " + distance);
double angle = (Math.PI / 2.0) - bearing;
int x = (int)(distance * scaleFactor * Math.cos(angle));
int y = (int)(distance * scaleFactor * Math.sin(angle));
// Assumes radar coordinate system has (0,0) at the lower left.
Radar.plotXY(x + width / 2, y + height / 2);
}
And here's the results I get:
Bearing: 102.38029388096368
Distance: 90.59766443003579
X: 184
Y: 116
(Your drone isn't actually to the north; The coordinates you gave place it to the east and a little south.)
Note that double precision is enough: "Double precision floats give sub-millimetre precision anywhere on Earth."
You might also be interested in a library like spatial4j for doing geographic calculations in Java.
When you go north, latitude increases up to 90 degrees at the north pole. So yes, you are correct. The pixels should be more positive. (You're in North America/Europe, I assume?) Read This
However, I'm working on a GPS project right now, and I can tell you from experience that 4 meters is far, far to close. Civilian GPS receivers without assistance from cell towers can get to about 10 meters of accuracy under ideal conditions. Maybe better with GLONASS.
If you're willing to wait, you can buy one of these:
http://store.swiftnav.com
GPS 101: Move the drone further away, and account for results that are only accurate to about 20 meters.

Extracting Yaw from a Quaternion

I have a rotation quaternion and want to extract the angle of rotation about the Up axis (the yaw). I am using XNA and as far as I can tell there is no inbuilt function for this. What is the best way to do this?
Thanks for any help,
Venatu
The quaternion representation of rotation is a variation on axis and angle. So if you rotate by r radians around axis x, y, z, then your quaternion q is:
q[0] = cos(r/2);
q[1] = sin(r/2)*x;
q[2] = sin(r/2)*y;
q[3] = sin(r/2)*z;
If you want to create a quaternion that only rotates around the y axis, you zero out the x and z axes and then re-normalize the quaternion:
q[1] = 0;
q[3] = 0;
double mag = sqrt(q[0]*q[0] + q[2]*q[2]);
q[0] /= mag;
q[2] /= mag;
If you want the resulting angle:
double ang = 2*acos(q[0]);
This assumes that the quaternion representation is stored: w,x,y,z. If both q[0] and q[2] are zero, or close to it, the resulting quaternion should just be {1,0,0,0}.
Having given a Quaternion q, you can calculate roll, pitch and yaw like this:
var yaw = atan2(2.0*(q.y*q.z + q.w*q.x), q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z);
var pitch = asin(-2.0*(q.x*q.z - q.w*q.y));
var roll = atan2(2.0*(q.x*q.y + q.w*q.z), q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z);
This should fit for intrinsic tait-bryan rotation of xyz-order. For other rotation orders, extrinsic and proper-euler rotations other conversions have to be used.
Note: I've verified below code against Wikipedia's equations plus Pixhawk's documentation and it is correct.
If you are working with drones/aviation, below is the code (taken directly from DJI SDK). Here q0, q1, q2, q3 corresponds to w,x,y,z components of the quaternion respectively. Also note that yaw, pitch, roll may be referred to as heading, attitude and bank respectively in some literature.
float roll = atan2(2.0 * (q.q3 * q.q2 + q.q0 * q.q1) , 1.0 - 2.0 * (q.q1 * q.q1 + q.q2 * q.q2));
float pitch = asin(2.0 * (q.q2 * q.q0 - q.q3 * q.q1));
float yaw = atan2(2.0 * (q.q3 * q.q0 + q.q1 * q.q2) , - 1.0 + 2.0 * (q.q0 * q.q0 + q.q1 * q.q1));
If you need to calculate all 3 then you can avoid recalculating common terms by using following functions:
//Source: http://docs.ros.org/latest-lts/api/dji_sdk_lib/html/DJI__Flight_8cpp_source.html#l00152
EulerianAngle Flight::toEulerianAngle(QuaternionData data)
{
EulerianAngle ans;
double q2sqr = data.q2 * data.q2;
double t0 = -2.0 * (q2sqr + data.q3 * data.q3) + 1.0;
double t1 = +2.0 * (data.q1 * data.q2 + data.q0 * data.q3);
double t2 = -2.0 * (data.q1 * data.q3 - data.q0 * data.q2);
double t3 = +2.0 * (data.q2 * data.q3 + data.q0 * data.q1);
double t4 = -2.0 * (data.q1 * data.q1 + q2sqr) + 1.0;
t2 = t2 > 1.0 ? 1.0 : t2;
t2 = t2 < -1.0 ? -1.0 : t2;
ans.pitch = asin(t2);
ans.roll = atan2(t3, t4);
ans.yaw = atan2(t1, t0);
return ans;
}
QuaternionData Flight::toQuaternion(EulerianAngle data)
{
QuaternionData ans;
double t0 = cos(data.yaw * 0.5);
double t1 = sin(data.yaw * 0.5);
double t2 = cos(data.roll * 0.5);
double t3 = sin(data.roll * 0.5);
double t4 = cos(data.pitch * 0.5);
double t5 = sin(data.pitch * 0.5);
ans.q0 = t2 * t4 * t0 + t3 * t5 * t1;
ans.q1 = t3 * t4 * t0 - t2 * t5 * t1;
ans.q2 = t2 * t5 * t0 + t3 * t4 * t1;
ans.q3 = t2 * t4 * t1 - t3 * t5 * t0;
return ans;
}
Note on Eigen Library
If you are using Eigen library, it has another way to do this conversion, however, this may not be as optimized as above direct code:
Vector3d euler = quaternion.toRotationMatrix().eulerAngles(2, 1, 0);
yaw = euler[0]; pitch = euler[1]; roll = euler[2];
Conversion Quaternion to Euler
I hope you know that yaw, pitch and roll are not good for arbitrary rotations. Euler angles suffer from singularities (see the above link) and instability. Look at 38:25 of the presentation of David Sachs
http://www.youtube.com/watch?v=C7JQ7Rpwn2k
Good luck!
A quaternion consists of two components: a 3d vector component and a scalar component.
The vector component of the quaternion describes independent rotations about each axis, so zero'ing out the x- and y-components of the vector component and leaving z-component as-is is all you need to do in order to solve for the vector term:
// Don't modify qz
double qx = 0;
double qy = 0;
The scalar term represents the magnitude of rotation. For a unit quaternion (such as one used to represent attitude), the entire quaternion must have a magnitude of 1. Thus, the scalar term can be solved by:
double qw = sqrt(1 - qx*qx - qy*qy - qz*qz);
Since qx and qy are zero, the scalar component is given by
double qw = sqrt(1 - qz*qz);
Thus, the full quaternion representing yaw is given by
double qx = 0;
double qy = 0;
// Don't modify qz
double qw = sqrt(1 - qz*qz);
The transformation from quaternion to yaw, pitch, and roll depends on the conventions used to define the quaternion and the yaw, pitch, and roll. For a given convention there are many "almost correct" transformations that will work for the majority of angles but only one truly correct transformation that will work for all angles including south and north poles where the "almost correct" transformations produce gimbal locks (spurious flips and rotations).
See this tutorial for more information:
https://youtu.be/k5i-vE5rZR0

how can I retrieve nearest restaurant detail using latitude and longitude

I am android developer and I want to retrieve nearest restaurant detail based on user entered latitude and longitude detail.
Already been answered here (distance between latitude and longitude coordinates).
To quote:
This link might be helpful to
you.
Excerpt:
This script calculates great-circle
distances between the two points –
that is, the shortest distance over
the earth’s surface – using the
‘Haversine’ formula.
Javascript:
var R = 6371; // Radius of the earth in km
var dLat = (lat2-lat1).toRad(); // Javascript functions in radians
var dLon = (lon2-lon1).toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
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
1:
http://www.movable-type.co.uk/scripts/latlong.html

Calculate second point knowing the starting point and distance

using a Latitude and Longitude value (Point A), I am trying to calculate another Point B, X meters away bearing 0 radians from point A. Then display the point B Latitude and Longitude values.
Example (Pseudo code):
PointA_Lat = x.xxxx;
PointA_Lng = x.xxxx;
Distance = 3; //Meters
bearing = 0; //radians
new_PointB = PointA-Distance;
I was able to calculate the distance between two Points but what I want to find is the second point knowing the distance and bearing.
Preferably in PHP or Javascript.
Thank you
It seems you are measuring distance (R) in meters, and bearing (theta) counterclockwise from due east. And for your purposes (hundereds of meters), plane geometry should be accurate enough. In that case,
dx = R*cos(theta) ; theta measured counterclockwise from due east
dy = R*sin(theta) ; dx, dy same units as R
If theta is measured clockwise from due north (for example, compass bearings),
the calculation for dx and dy is slightly different:
dx = R*sin(theta) ; theta measured clockwise from due north
dy = R*cos(theta) ; dx, dy same units as R
In either case, the change in degrees longitude and latitude is:
delta_longitude = dx/(111320*cos(latitude)) ; dx, dy in meters
delta_latitude = dy/110540 ; result in degrees long/lat
The difference between the constants 110540 and 111320 is due to the earth's oblateness
(polar and equatorial circumferences are different).
Here's a worked example, using the parameters from a later question of yours:
Given a start location at longitude -87.62788 degrees, latitude 41.88592 degrees,
find the coordinates of the point 500 meters northwest from the start location.
If we're measuring angles counterclockwise from due east, "northwest" corresponds
to theta=135 degrees. R is 500 meters.
dx = R*cos(theta)
= 500 * cos(135 deg)
= -353.55 meters
dy = R*sin(theta)
= 500 * sin(135 deg)
= +353.55 meters
delta_longitude = dx/(111320*cos(latitude))
= -353.55/(111320*cos(41.88592 deg))
= -.004266 deg (approx -15.36 arcsec)
delta_latitude = dy/110540
= 353.55/110540
= .003198 deg (approx 11.51 arcsec)
Final longitude = start_longitude + delta_longitude
= -87.62788 - .004266
= -87.632146
Final latitude = start_latitude + delta_latitude
= 41.88592 + .003198
= 41.889118
It might help if you knew that 3600 seconds of arc is 1 degree (lat. or long.), that there are 1852 meters in a nautical mile, and a nautical mile is 1 second of arc. Of course you're depending on the distances being relatively short, otherwise you'd have to use spherical trigonometry.
Here is an updated version using Swift:
let location = CLLocation(latitude: 41.88592 as CLLocationDegrees, longitude: -87.62788 as CLLocationDegrees)
let distanceInMeter : Int = 500
let directionInDegrees : Int = 135
let lat = location.coordinate.latitude
let long = location.coordinate.longitude
let radDirection : CGFloat = Double(directionInDegrees).degreesToRadians
let dx = Double(distanceInMeter) * cos(Double(radDirection))
let dy = Double(distanceInMeter) * sin(Double(radDirection))
let radLat : CGFloat = Double(lat).degreesToRadians
let deltaLongitude = dx/(111320 * Double(cos(radLat)))
let deltaLatitude = dy/110540
let endLat = lat + deltaLatitude
let endLong = long + deltaLongitude
Using this extension:
extension Double {
var degreesToRadians : CGFloat {
return CGFloat(self) * CGFloat(M_PI) / 180.0
}
}
dx = sin(bearing)
dy = cos(bearing)
x = center.x + distdx;
y = center.y + distdy;

Resources