Get lat/long given current point, distance and bearing
Needed to convert answers from radians back to degrees. Working code below:
import math
R = 6378.1 #Radius of the Earth
brng = 1.57 #Bearing is 90 degrees converted to radians.
d = 15 #Distance in km
#lat2 52.20444 - the lat result I'm hoping for
#lon2 0.36056 - the long result I'm hoping for.
lat1 = math.radians(52.20472) #Current lat point converted to radians
lon1 = math.radians(0.14056) #Current long point converted to radians
lat2 = math.asin( math.sin(lat1)*math.cos(d/R) +
math.cos(lat1)*math.sin(d/R)*math.cos(brng))
lon2 = lon1 + math.atan2(math.sin(brng)*math.sin(d/R)*math.cos(lat1),
math.cos(d/R)-math.sin(lat1)*math.sin(lat2))
lat2 = math.degrees(lat2)
lon2 = math.degrees(lon2)
print(lat2)
print(lon2)
Find destination coordinates given starting coordinates, bearing, and distance
According to this page
math.sin(x)
... Return the sine of x radians.
So, you need to convert lat1 and lon1 to radians before your equation and then later you can convert lat2 and lon2 back into degrees.
Get accurate lat/long given current point, distance and bearing
You can use the spherical geometry utilities of the Google Maps SDK for Android utility library.
The specific method that you can use will be the computeOffset method. You can see it when you search the SphericalUtil in this link.
ComputeOffset returns the LatLng resulting from moving a distance from an origin in the specified heading (expressed in degrees clockwise from north). Here are the parameters that you need to specify:
from - The LatLng from which to start.
distance - The distance to travel.
heading - The heading in degrees clockwise from north.
To use this, add the utility library to your dependencies:
implementation 'com.google.maps.android:android-maps-utils:0.5'
This is the sample of a line of code that I use:
LatLng newCoordinates = SphericalUtil.computeOffset(new LatLng(-25.363, 131.044),30000, 90);
Hope this helps!
calculating Lat and Long from Bearing and Distance
Your problem is on your first line.
Try
double dist = 150.0 / 6371.0;
The reason is that 150/6371
gets calculated as 0
, because it performs integer division (rather than floating point division). This is true even though the result is being stored in a double
. You can force floating point division by making one of the two numbers a floating point literal.
Attempting to calculate lat and long given distance and bearing from start point
Here is my code that solved the problem:
public static (double Lat, double Lon) Destination((double Lat, double Lon) startPoint, double distance, double bearing)
{
double φ1 = startPoint.Lat * (Math.PI / 180);
double λ1 = startPoint.Lon * (Math.PI / 180);
double brng = bearing * (Math.PI / 180);
double φ2 = Math.Asin(Math.Sin(φ1) * Math.Cos(distance / radius) + Math.Cos(φ1) * Math.Sin(distance / radius) * Math.Cos(brng));
double λ2 = λ1 + Math.Atan2(Math.Sin(brng) * Math.Sin(distance / radius) * Math.Cos(φ1), Math.Cos(distance / radius) - Math.Sin(φ1) * Math.Sin(φ2));
return (φ2 * (180 / Math.PI), λ2 * (180 / Math.PI));
}
radius
is the radius of the Earth in meters.
Calculating coordinates given a bearing and a distance
It seems like these are the issues in your code:
- You need to convert
lat1
andlon1
to radians before calling your function. - You may be scaling
radialDistance
incorrectly. - Testing a floating-point number for equality is dangerous. Two numbers that are equal after exact arithmetic might not be exactly equal after floating-point arithmetic. Thus
abs(x-y) < threshold
is safer thanx == y
for testing two floating-point numbersx
andy
for equality. - I think you want to convert
lat
andlon
from radians to degrees.
Here is my implementation of your code in Python:
#!/usr/bin/env python
from math import asin,cos,pi,sin
rEarth = 6371.01 # Earth's average radius in km
epsilon = 0.000001 # threshold for floating-point equality
def deg2rad(angle):
return angle*pi/180
def rad2deg(angle):
return angle*180/pi
def pointRadialDistance(lat1, lon1, bearing, distance):
"""
Return final coordinates (lat2,lon2) [in degrees] given initial coordinates
(lat1,lon1) [in degrees] and a bearing [in degrees] and distance [in km]
"""
rlat1 = deg2rad(lat1)
rlon1 = deg2rad(lon1)
rbearing = deg2rad(bearing)
rdistance = distance / rEarth # normalize linear distance to radian angle
rlat = asin( sin(rlat1) * cos(rdistance) + cos(rlat1) * sin(rdistance) * cos(rbearing) )
if cos(rlat) == 0 or abs(cos(rlat)) < epsilon: # Endpoint a pole
rlon=rlon1
else:
rlon = ( (rlon1 - asin( sin(rbearing)* sin(rdistance) / cos(rlat) ) + pi ) % (2*pi) ) - pi
lat = rad2deg(rlat)
lon = rad2deg(rlon)
return (lat, lon)
def main():
print "lat1 \t lon1 \t\t bear \t dist \t\t lat2 \t\t lon2"
testcases = []
testcases.append((0,0,0,1))
testcases.append((0,0,90,1))
testcases.append((0,0,0,100))
testcases.append((0,0,90,100))
testcases.append((49.25705,-123.140259,225,1))
testcases.append((49.25705,-123.140259,225,100))
testcases.append((49.25705,-123.140259,225,1000))
for lat1, lon1, bear, dist in testcases:
(lat,lon) = pointRadialDistance(lat1,lon1,bear,dist)
print "%6.2f \t %6.2f \t %4.1f \t %6.1f \t %6.2f \t %6.2f" % (lat1,lon1,bear,dist,lat,lon)
if __name__ == "__main__":
main()
Here is the output:
lat1 lon1 bear dist lat2 lon2
0.00 0.00 0.0 1.0 0.01 0.00
0.00 0.00 90.0 1.0 0.00 -0.01
0.00 0.00 0.0 100.0 0.90 0.00
0.00 0.00 90.0 100.0 0.00 -0.90
49.26 -123.14 225.0 1.0 49.25 -123.13
49.26 -123.14 225.0 100.0 48.62 -122.18
49.26 -123.14 225.0 1000.0 42.55 -114.51
Given point of (latitude,longitude), distance and bearing, How to get the new latitude and longitude
This is a prime example of why commenting your code makes it more readable and maintainable. Mathematically you are looking at the following:
double ec = 6356725 + 21412 * (90.0 - LAT) / 90.0; //why?
This is a measure of eccentricity to account for the equatorial bulge in some fashion. 21412
is, as you know, the difference in earth radius between the equator and pole. 6356725
is the polar radius. (90.0 - LAT) / 90.0
is 1
at the equator, and 0
at the pole. The formula simply estimates how much bulge is present at any given latitude.
double ed = ec * Math.Cos(LAT * Math.PI / 180); // why?
(LAT * Math.PI / 180)
is a conversion of latitude from degrees to radians. cos (0) = 1
and cos(1) = 0
, so at the equator, you are applying the full amount of the eccentricity while at the pole you are applying none. Similar to the preceding line.
dx / ed //why?
dy / ec //why?
The above seems to be the fractional additions to distance in both the x
and y
directions attributable to the bulge at any given lat/lon used in the newLon
newLat
computation to arrive at the new location.
I haven't done any research into the code snippet you found, but mathematically, this is what is taking place. Hopefully that will steer you in the right direction.
Haversine Example in C
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double m2ft (double l) { /* convert meters to feet */
return l/(1200.0/3937.0);
}
double ft2smi (double l) { /* convert feet to statute miles*/
return l/5280.0;
}
double km2smi (double l) { /* convert km to statute mi. */
return ft2smi(m2ft( l * 1000.0 ));
}
static const double deg2rad = 0.017453292519943295769236907684886;
static const double earth_rad_m = 6372797.560856;
typedef struct pointd {
double lat;
double lon;
} pointd;
/* Computes the arc, in radian, between two WGS-84 positions.
The result is equal to Distance(from,to)/earth_rad_m
= 2*asin(sqrt(h(d/earth_rad_m )))
where:
d is the distance in meters between 'from' and 'to' positions.
h is the haversine function: h(x)=sin²(x/2)
The haversine formula gives:
h(d/R) = h(from.lat-to.lat)+h(from.lon-to.lon)+cos(from.lat)*cos(to.lat)
http://en.wikipedia.org/wiki/Law_of_haversines
*/
double arcradians (const pointd *from, const pointd *to)
{
double latitudeArc = (from-> lat - to-> lat) * deg2rad;
double longitudeArc = (from-> lon - to-> lon) * deg2rad;
double latitudeH = sin (latitudeArc * 0.5);
latitudeH *= latitudeH;
double lontitudeH = sin (longitudeArc * 0.5);
lontitudeH *= lontitudeH;
double tmp = cos (from-> lat * deg2rad) * cos (to-> lat * deg2rad);
return 2.0 * asin (sqrt (latitudeH + tmp*lontitudeH));
}
/* Computes the distance, in meters, between two WGS-84 positions.
The result is equal to earth_rad_m*ArcInRadians(from,to)
*/
double dist_m (const pointd *from, const pointd *to) {
return earth_rad_m * arcradians (from, to);
}
int main (int argc, char **argv) {
if (argc < 5 ) {
fprintf (stderr, "Error: insufficient input, usage: %s (lat,lon) (lat,lon)\n", argv[0]);
return 1;
}
pointd points[2];
points[0].lat = strtod (argv[1], NULL);
points[0].lon = strtod (argv[2], NULL);
points[1].lat = strtod (argv[3], NULL);
points[1].lon = strtod (argv[4], NULL);
printf ("\nThe distance in meters from 1 to 2 (smi): %lf\n\n", km2smi (dist_m (&points[0], &points[1])/1000.0) );
return 0;
}
/* Results/Example.
./bin/gce 31.77 -94.61 31.44 -94.698
The distance in miles from Nacogdoches to Lufkin, Texas (smi): 23.387997 miles
*/
Calculate second point knowing the starting point and distance
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
Related Topics
How to Create Animated Sprites Using Sprite Sheets in Pygame
How to Dynamically Compose an or Query Filter in Django
How to Determine Whether a Year Is a Leap Year
Attributeerror: 'Tensor' Object Has No Attribute 'Numpy'
How to Save an Image Locally Using Python Whose Url Address I Already Know
How to Send Cookies in a Post Request with the Python Requests Library
Reading a Binary File with Python
How to Do/Workaround a Conditional Join in Python Pandas
How to Make a Surface with a Transparent Background in Pygame
Complexity of *In* Operator in Python
If X:, VS If X == True, VS If X Is True
Separation of Business Logic and Data Access in Django
Django Db Settings 'Improperly Configured' Error
How to Generate a Random Number with a Specific Amount of Digits
How to Make a For-Loop Pyramid More Concise in Python