So: I have the following function, adapted from a formula found online, which takes two lat/lon coordinates and finds the distance between them in miles (along a spherical Earth):
public static double distance (double lat1, double lon1, double lat2, double lon2) {
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;
}
As far as I can tell this works just fine.
What I need is a second function which, using the exact same model of the Earth's geometry, takes a single lat/lon pair [A], a heading, and a distance, and outputs a new lat/lon pair [B] such that if you started at point [A], and traveled the given distance at the given heading, you'd wind up at point [B].
This is where the fact that my geometry skills have left me entirely comes into play :)
Any help would be much appreciated!
Thanks,
-Dan
I get most of those types of formulas from The Aviation Formulary.
The formula he gives is:
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
This algorithm is limited to distances such that dlon < pi/2, i.e
those that extend around less than one
quarter of the circumference of the
earth in longitude. A completely
general, but more complicated
algorithm is necessary if greater
distances are allowed:
lat =asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
dlon=atan2(sin(tc)*sin(d)*cos(lat1),cos(d)-sin(lat1)*sin(lat))
lon=mod( lon1-dlon +pi,2*pi )-pi
Note that he's using "tc" to stand for true course (in radians clockwise from North) and the distances he gives are in radians of arc along the surface of the earth. This is explained (along with formulas to convert back and forth from nautical miles) in the first section of the Formulary. Also, check out the "Implementation Notes" and "Worked Examples" on that page.
Related
I am trying to calculate bearing between two lat/lon points as given in this link. I see that the bearing we get initially using the below equation is initial bearing.
public static double GetBearing(double latitude1, double longitude1, double latitude2, double longitude2)
{
var lat1 = ToRadians(latitude1);
var lat2 = ToRadians(latitude2);
var longdiff = ToRadians(longitude1 - longitude2);
var X = Math.Cos(lat2) * Math.Sin(longdiff);
var Y = Math.Cos(lat1) * Math.Sin(lat2) - Math.Sin(lat1) * Math.Cos(lat2) * Math.Cos(longdiff);
var bearing =ToDegrees(Math.Atan2(X, Y));
return (bearing+360)%360;
}
It is given that
For final bearing, simply take the initial bearing from the end point to the start point and reverse it (using θ = (θ+180) % 360).
I am confused about the difference between initial bearing and final bearing.
What is this initial and final bearing and which bearing should we take as the final answer for bearing between two points.
The bearing is the angle between direction along the shortest path to destination and direction to North. The reason we have initial and final one is that we live on sphere, so the shortest path is geodesic line. It is a straight line on globe, bit if you draw it on flat map - it will be a curve.
There are two ways to think about it. Thinking on flat map: as you travel from A to B, this curve changes direction slightly, so the angle between this line and North changes, i.e. bearing changes.
Or you can think on sphere, and then think about triangle A - B - North Pole. The bearing is angle between between AB and appropriate meridian. Initial bearing is angle between AB and meridian crossing A. Final one is angle between AB and meridian crossing B. They are different.
The single "final answer" bearing only makes sense when distance between A and B is short. Then the curvature of Earth does not matter much, and the initial and final bearings are very close to each other, so depending on precision needed one can talk about single bearing.
FYI: bearing and many related computations are implemented in the R package geosphere
The bearing function returns the initial bearing, but you can invert the coordinates to get the final bearing.
library(geosphere)
bearing(cbind(0,0),cbind(20,20))
#[1] 43.4035
finalb <- bearing(cbind(20,20),cbind(0,0))
(finalb + 180) %% 360
#[1] 46.9656
(these results should be more precise than the ones you get with algorithm you refer to)
def bearing(lat1, lon1, lat2, lon2):
# Convert latitude and longitude to radians
lat1 = math.radians(lat1)
lon1 = math.radians(lon1)
lat2 = math.radians(lat2)
lon2 = math.radians(lon2)
y = math.sin(lon2-lon1) * math.cos(lat2)
x = math.cos(lat1)*math.sin(lat2) - math.sin(lat1)*math.cos(lat2)*math.cos(lon2-lon1)
initial_bearing = math.degrees(math.atan2(y, x))
final_bearing = (initial_bearing + 180) % 360 if initial_bearing < 180 else (initial_bearing - 180) % 360
return initial_bearing, final_bearing
I have pairs of gps coordinates (longitude latitude) and I would like to calculate the walking distance between them. i.e. using road data (from google maps or another open source) calculate the km of the shortest route between the two gps points. I could do it using google maps, but I have thousands of pairs so I would like to find a more automated way.
Does somebody know how to do it?
I am not quite sure about what you looking for. Just share some thoughts here:
1) If you want to calculate great circle distance between two points in lat/lon, you could use haversine formula distance. Example in JS:
function Haversine_distance(lat1,lon1,lat2,lon2) {
var R = 6371; // in km
var x1 = lat2 - lat1;
var dLat = x1.toRad();
var x2 = lon2 - lon1;
var dLon = x2.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;
return d*1.0;
};
2) If you need more accurate distance calculation you need some correction factor, since earth is not a perfer sphere. It is always easier to project the locations you have to an appropriate projection and calculate distance there. For instance, project to UTM zones using proj4js, then calculate the distance to reduce the inaccuracy.
3) If you are talking about walking distance in cities, then it is network distance. It is required to have your road network build up first, then calculate from there. Without the road network, giving only point locations will not be enough to calculate the walking distance. Commercial data for road network is available from such as TeleAtlas. Free data can also be found via OpenStreetMap.
If I have a column called Poly of type polygon in MySQL and I want to get the NW corner and the NE corner and the SE corner and the SW corner, how would I do that? From an Envelope() there should be lat1, lat2, lon1, and lon2 that form the four corners as follows lat1,lon1 is NW; lat1,lon2 is NE; lat2,lon2 is SE; and lat2,lon1 is SW. When I try X(PointN(Envelope(Poly),1)) AS lat1 it always returns NULL. Can this be done in MySQL?
SELECT
X(PointN(Envelope(Poly),1)) AS lat1, X(PointN(Envelope(Poly),3)) AS lat2,
Y(PointN(Envelope(Poly),1)) AS lon1, Y(PointN(Envelope(Poly),2)) AS lon2
FROM boundaries.mt_us_zip5_2013_boundaries_polys_bin
WHERE zip = '00601';
The query above returns:
NULL,NULL,NULL,NULL
Here's what the Envelope looks like:
SELECT AsText(Envelope(Poly))
FROM boundaries.mt_us_zip5_2013_boundaries_polys_bin
WHERE zip = '00601';
This last query returns:
POLYGON((18.111929 -66.836366,18.250344 -66.836366,18.250344 -66.659293,18.111929 -66.659293,18.111929 -66.836366))
I'm using MySQL version 5.5.36, would upgrading to a new version of MySQL give me the functions I need?
PointN is only defined on LineString, but luckily you can call ExteriorRing on the Polygon to get a LineString. In your example:
SELECT
X(PointN(ExteriorRing(Envelope(Poly)),1)) AS lat1,
X(PointN(ExteriorRing(Envelope(Poly)),3)) AS lat2,
Y(PointN(ExteriorRing(Envelope(Poly)),1)) AS lon1,
Y(PointN(ExteriorRing(Envelope(Poly)),2)) AS lon2
FROM boundaries.mt_us_zip5_2013_boundaries_polys_bin
WHERE zip = '00601';
I'm not familiar enough with MySQL if it has this built-in but my first thought was to first find in the center of the polygon, then compute the bearing at each point on the poly from the center. A bearing of 0 would be north and a bearing of 90 deg would be east, thus north-east would be 45 deg. Find the points closest to the 45 deg angles gives you the corners.
Center of the polygon is here: Computing latitude longitude center point of a Polygon in PHP
Computing bearing from 2 lat/lon points: http://www.movable-type.co.uk/scripts/latlong.html
I am trying to calculate approximate distance between two points with respect to road map on Google Maps. 75% of the time the points are not on a straight line, and they form a triangle on the road map. I am taking right angle as well as obtuse angle into consideration. And the line created by the points to be the hypotenuse.
Lets take the line formed by the points: "x"
Other Two lines: "y" & "z"
Assuming y and z equal
Now I am taking two options as stated earlier for best result:
Option 1:
y = x(sin 45)/(sin90)
Total Distance = 2y
Option 2:
y = x(sin 30)/(sin120)
Total Distance = 2y
On calculation the distance by getting the all the coordinates of the distance. It is different from both at and approximately 10 to 20%.
In almost all cases the second one provides the best value on checking with the Google Maps vehicle distance.
Is there any better alternative for maximum accuracy?
Did you try Haversine formula?
which is:
dlon = lon2 - lon1
dlat = lat2 - lat1
a = (sin(dlat/2))^2 + cos(lat1) * cos(lat2) * (sin(dlon/2))^2
c = 2 * atan2(sqrt(a), sqrt(1-a))
d = R * c
I'm trying to find a function lng = f(lat) that would help me draw a line between 2 given GPS coordinates, (lat1, lng1) and (lat2, lng2).
I've tried the traditional Cartesian formula y=mx+b where m=(y2-y1)/(x2-x1), but GPS coordinates don't seem to behave that way.
What would be a formula/algorithm that could help me achieve my goal.
PS: I'm using Google Maps API but let's keep this implementation agnostic if possible.
UPDATE: My implementation was wrong and it seems the algorithm is actually working as stated by some of the answers. My bad :(
What you want to do should actually work. Keep in mind however that if north is on top, the horizontal (x) axis is the LONGITUDE and the vertical (y) axis is the LATITUDE (I think you might have confused this).
If you parametrize the line as lat = func(long) you will run into trouble with vertical lines (i.e. those going exactly north south) as the latitude varies while the longitude is fixed.
Therefore I'd rather use another parametrization:
long(alpha) = long_1 + alpha * (long_2 - long_1)
lat(alpha) = lat_1 + alpha * (lat_2 - lat_1)
and vary alpha from 0 to 1.
This will not exactly coincide with a great circle (shortest path on a sphere) but the smaller the region you are looking at, the less noticeable the difference will be (as others posters here pointed out).
Here is a distance formula I use that may help. This is using javascript.
function Distance(lat1, lat2, lon1, lon2) {
var R = 6371; // km
var dLat = toRad(lat2 - lat1);
var dLon = toRad(lon2 - lon1);
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(toRad(lat1)) * Math.cos(toRad(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 * 0.621371;
var r = Math.round(d * 100) / 100;
return r;
}
For short distances, where the earth curvature doesn't make a significant difference, it works fine to draw a line using regular two-dimensional geometry.
For longer distances the shortest way between two lines does not project as a straight line on a map, but as a curve. (For example, the shortest way from Sweden to Alaska would be straight over the noth pole, not past Canada and Iceland.) You would have to use three-dimensional geometry to draw a line on a surface of a sphere, then project that onto the map in the same way the earth surface is projected on the map.
Is your goal to find this equation or to actually draw a line?
If the latter, since you're using the Maps API, specify geodesic: true and draw it with a Polyline:
http://code.google.com/apis/maps/documentation/javascript/reference.html#Polyline