I have this problem I have to solve.
I am given a coordinate lat/lon, and I need to find a random point within 3 meters of this original point. Approximations are good, but all I could find was this https://gis.stackexchange.com/questions/2951/algorithm-for-offsetting-a-latitude-longitude-by-some-amount-of-meters that has a 10 meter error. Thank you.
Not sure what "find" and "random" mean in this question.
The earth is about 10 million meters from equator to either pole (that's actually how they defined the size of the meter, at first; it's been modified slightly since). The width of latitude lines doesn't vary, so one meter north or south is always is one ten-millionth of 90 degrees, or 9e-6 degrees, so just multiply that by the north-south displacement in meters of your desired point from the initial point and you'll get the number to add to the initial point in degrees: delta_lat = y_meters * 9e-6.
The width of longitude lines does vary, but it works out as simply east-west displacement in meters * 9e-6 = delta_lon * cos(lat), which means you can use the distance from your initial point to figure the east-west difference in degrees: delta_lon = x_meters * 9e-6/cos(lat).
You'll have to be careful with that last part around the poles, because cos(lat) will approach zero. Navigational systems use quaternions to do these things because they don't have singularities in spherical coordinates.
Related
I have a service that looks for nearby locations(300m) from a user specified point.
I'm using the haversine formula to check if a location is near the point
https://en.wikipedia.org/wiki/Haversine_formula
My problem is that it's slow since it's checking against all of the points in my DB.
What I want to do is limit the initial query and apply the haversine formula to a list of points in a smaller bounded area
e.g.
results = (SELECT * FROM location WHERE location.latitude BETWEEN 14.223 AND 14.5 )
AND location.longitude BETWEEN 121.5 AND 122
haversine(results, user_point)
Is there a loose way of getting the bounds from a given point?
Or basically a dirty conversion of lat/long to meters?
If you can modify your database structure, there's one super-easy way to do it: instead of (or in addition to) storing latitude and longitude, convert your location coordinates into 3D space, with columns for x, y, and z in meters. Then you can just do
SELECT * FROM location
WHERE location.x BETWEEN center.x - 300 AND center.x + 300
AND location.y BETWEEN center.y - 300 AND center.y + 300
AND location.z BETWEEN center.z - 300 AND center.z + 300
That will trim down your list pretty well, and you can do the haversine calculation on the resulting set.
If you're stuck with using a database that has only longitude and latitude in it, you can still narrow down the search. It's easy for latitude: one degree of latitude due north or south always corresponds to 111 km of distance, as long as you ignore the complications that arise when you get close to the poles. That means a distance of 300 m is 0.0027... degrees of latitude, although you might as well be a bit conservative and use 0.003 or 0.004.
Longitude is a bit trickier because the conversion factor changes depending on how far north or south you are, but it's still not too complicated: you just multiply by the cosine of the latitude.
distance = cos(latitude) * 111.19... km/degree * delta_angle
At the equator, it's the same as with latitude: one degree change in longitude at the equator is 111 km. At 80 degrees north (or south), you multiply by a factor of cos(80 degrees) = 0.17..., with the result that 1 degree change in longitude is only 19.3 km. For your purposes, you could invert this and find the range of longitudes to select as 300 m / cos(latitude) / (111.19... km/degree) = (0.0027... degrees) / cos(latitude). That coefficient is the same quantity from the first paragraph; it's not a coincidence.
The tricky problems come up near the discontinuities of the coordinate system, for example when you get near the poles. You can see why when you start plugging in latitudes like 89.9996 degrees:
0.0027... degrees / cos(89.9996 degrees) = 386... degrees
Well, how can that be when there are only 360 degrees in a whole circle? This is an indicator that you've gotten to the point where your 300 m radius extends all the way around the pole and comes back to include your starting location, in a manner of speaking. At that point, you might as well just search all points in your database close enough to the pole. Of course you should really start doing this at 89.999 degrees or so, because that's where the 600 m diameter of the region you're searching just about encircles the pole completely.
There's another issue at (well, near) the International Date Line, or more precisely the "antimeridian", having to do with the jump from -180 to +180 degrees of longitude. A point at +179.9999 degrees and one at -179.9999 degrees, both on the equator, will have very different coordinates even though they are geographically just a few meters apart. Since you're just doing this as a preliminary filter for a more detailed search, it's probably easiest to just pass through every point within 0.006 degrees (that's roughly the diameter of a 300 m-radius circle) of the antimeridian, and then the haversine calculation will determine whether the points are actually close.
To sum up, you can use the bounds on latitude and longitude I mentioned above and just add special cases for the poles and the antimeridian. In some kind of pseudo-SQL/code hybrid:
IF abs(center.latitude) > 89.999
SELECT * FROM location WHERE abs(location.latitude - center.latitude) < 0.003
ELSE
IF abs(center.longitude) > 179.997
SELECT * FROM location
WHERE abs(location.latitude - center.latitude) < 0.003
AND 180 - abs(location.longitude) < (0.006 / cos(center.latitude))
ELSE
SELECT * FROM location
WHERE abs(location.latitude - center.latitude) < 0.003
AND abs(location.longitude - center.longitude) < (0.003 / cos(center.latitude))
ENDIF
ENDIF
If you want a pithy statement at the expense of having to test potentially twice as many points, you can only compare the absolute values of longitude:
SELECT * FROM location
WHERE abs(location.latitude - center.latitude) < 0.003
AND abs(abs(location.longitude) - abs(center.longitude)) <= min(0.003 / cos(center.latitude), 180)
Approximating the earth with a sphere, the distance between two consecutive latitudes can be calculated by
dPerLat = pi * r / 180°,
where r is the radius of the earth. This will be about 111 km.
So, if your reference point is (lat, long) and your search radius is d then you want to search for latitudes in the range
lat* \in [lat - d / dPerLat, lat + d / dPerLat]
Then, for a given latitude, the distance of consecutive longitudes is:
dPerLong = pi * r * cos(lat) / 180°
Again, the range of longitudes to search is +- d / dPerLong. You should use the lat value that gives you a conservative (maximal) range, i.e. the lat value with the highest absolute value.
Be careful at the poles.
I have a set of latitudes and longitudes , so this is the data for an animal as it moves in time. what i want to do is to calculate turning angle, that is by what angle it turns between every movement. so say i have point 1, point 2 and point 3 with latitude and longitude value corresponding to each point(animal moves from point 1 to point 2 to point 3 and so on) and i want to calculate the angle between these 3 points, point 2 being the middle point. what should i do? my OS is windows and i am using R for analysis.
so here is my sample data:
longitude latitude
36.89379547 0.290166977
36.89384037 0.290194109
36.88999724 0.286821044
36.88708721 0.288339411
36.88650313 0.29010232
36.88563203 0.289939416
36.88545224 0.290924863
they are in decimal degrees
Using the function trackAzimuth in maptools:
library(maptools)
trackAngle <- function(xy) {
angles <- abs(c(trackAzimuth(xy), 0) -
c(0, rev(trackAzimuth(xy[nrow(xy):1, ]))))
angles <- ifelse(angles > 180, 360 - angles, angles)
angles[is.na(angles)] <- 180
angles[-c(1, length(angles))]
}
The trackAzimuth function is a simple loop wrapper around gzAzimuth. See ?gzAzimuth for references on calculating directions on the sphere.
Using your data:
x <- read.table(text = "longitude latitude
36.89379547 0.290166977
36.89384037 0.290194109
36.88999724 0.286821044
36.88708721 0.288339411
36.88650313 0.29010232
36.88563203 0.289939416
36.88545224 0.290924863", header = TRUE)
trackAngle(as.matrix(x))
[1] 10.12946 111.17211 135.88514 97.73801 89.74684
EDIT: I had to remove first/last angles from the function, something I was doing after the fact with this function elsewhere. Should be right now. :)
Also, the packages adehabitatLT and argosfilter contain functions to calculate track directions and angles.
Your data points vary over only a small range. We can look at one small patch of Earth's surface and pretend it's flat, two dimensional. You have to figure out the scale of how many km, meters, miles, whatever your favorite unit is, corresponds to one degree of latitude, and for one degree of longitude. The latter depends on latitude - it'll be the same as the scale for latitude when near the equator, but if you are standing within arm's length of the north pole, one step will take you through fifty degrees. Set up x,y coordinates where x=0 is at longitude 36.88000, and y=0 is latitude 0.29000.
So, now you have a series of (x,y) points. Take the differences from each point to the next: P2-P1, P3-P2, etc. These could be called "displacement vectors" but other terms may be used in other fields than where i'm from. Call them V1, V2, etc. Use dot products and norms: dot(V1,V2) = magnitude(V1)*magnitude(V2)*cos(a) where a is the angle by which V2 deviates from the direction of V1. Repeat for V3 and V2, and so on.
R has all the tools to do this, but I don't know enough syntax of R to give examples.
I'm trying to write an algorithm that does the following.
Given a current position (in Azimuth and Inclination) and a target position (again in A, I) in what direction should I travel to travel over the shortest path. The return value could be something like a vector A = -1, I = +0.5, that I can then scale for step size/time.
The shortest path can be found by using a great circle, this is easy to visualize, but it's hard to implement like above because my coordinate system isn't continuous.
My coordinate system is as followed (imagine standing in front of the sphere)
The azimuth is 0 ~ pi when traveling along the equator along the front side, it's 0 ~ -pi when traveling along the equator along the rear side.
The inclination is 0~+pi when traveling from the top to the bottom of the sphere.
So given this non-continuous coordinate system, how do I create a decision function that says 'increase A' to travel over the shortest path?
You have a couple of alternatives. The first is to use a Haversine formulation. There is some Javascript source code here. It requires using more traditional lat / lon where the equator is at 0 latitude and the poles are at +/- π or +/- 90° latitude (depending on your units) and longitude is in the range [-180°, 180°) or [-π, π) again depending on your units. You can repeatedly find the midpoint until you have an approximate path that suites your needs. The azimuth / inclination vector would just be the difference in lat / lon between two adjacent points, though over time this will likely induce an error if you repeatedly apply those lat / lon deltas to the location of your agent.
Another approach that may work well for you is to transform your spherical coordinates of your starting and ending location to cartesian coordinates, call them points ub and ue for beginning and end points. The normal vector v of the great circle connecting the two points is the cross product of the two (i.e. v = ub x ue) and the angle θ is just the arccosine of the normalized inner product (ie. θ = cos-1( (ue ∙ ue) / (|ub||ue)). You can then use quaternion rotation and iterate from 0 to θ about the vector v to actually navigate the path. With this approach, the actual instantaneous vector at some point p along the path is just the p x v, or you can just approximate this by using the cartesian difference between two adjacent points along the path.
I'm wondering if it's possible to find all points by longitude and latitude within X radius of one point?
So, if I provide a latitude/longitude of -76.0000, 38.0000, is it possible to simply find all the possible coordinates within (for example) a 10 mile radius of that?
I know that there's a way to calculate the distance between two points, which is why I'm not clear as to whether this is possible. Because, it seems like you need to know the center coordinates (-76 and 38 in this case) as well as the coordinates of every other point in order to determine whether it falls within the specified radius. Is that right?
#David's strategy is correct, his implementation is seriously flawed. I suggest that before you perform the calculations you transform your lat,long pair to UTM coordinates and work in distance, not angular, measurements. If you are not familiar with Universal Transverse Mercator, hit Google or Wikipedia.
I reckon that your point (-76,38) is at UTM 37C 472995 (Easting) 1564346 (Northing). So you want to do your calculations of distance from that point. You'll find it easier, working with UTM, to work in metres, so your distance is (if you are using statute miles of 5280 feet) 16040 metres.
Incidentally, (-76,38) is well outside the contintental US -- does the US Post Office define zip codes for Antarctica ?
If you accept that the Earth is a perfect sphere, you can obtain the spatial coordinates of a point by
x = R.cos(Lat).cos(Long)
y = R.cos(Lat).sin(Long)
z = R.sin(Lat)
Now, take two points and compute the angle they form with the center of the Earth (using a dot product):
cos(Phi) = (x'.x" + y'.y" + z'.z") / R²
(the value of R gets simplified).
In your case, the angular distance, Phi, equals 2Pi.D/R. (R=6 378.1 km).
A point P" is inside the ground distance (D) of P' when the dot product is larger than cos(Phi).
CAUTION: all angles must be in radians.
Depending on the precision, the data set of points within a certain distance may be extremely large or even infinite (impossible). In a given area of a circle with a positive radius you will have infinitely many points. Thus, it is trivial to determine if a point falls within a circle, however to enumerate over all the points is impossible.
If you do set a fixed precision (such as a single digit), you can loop over all possible latitude and longitude combinations and perform the distance test.
Kevin is correct. There is no reason to calculate every possible coordinate-pair in the radius.
If you start at the centerpoint pC = Point(-76.0000, 38.0000) and are testing to find out if arbitrary point pA = Point(Ax, Ay) is within a 10 mile radius... use the Pythagorean theorem:
xDist = abs( pCx - Ax )
yDist = abs ( pCy - Ay )
r^2 = (xDist)^2 + (yDist)^2
A reasonable approximation is to only query the points where
pAx >= (-76.0000 - 10.0000) && pAx <= (-76.0000 + 10.0000)
pAy >= ( 38.0000 - 10.0000) && pAy <= ( 38.0000 + 10.0000)
then perform the more intensive calculation above.
What is the maximum length (in kilometers or miles - but please specify) that one degree of latitude and longitude can have in the Earth surface?
I'm not sure if I'm being clear enough, let me rephrase that. The Earth is not a perfect circle, as we all know, and a change of 1.0 in the latitude / longitude on the equator (or in Ecuador) can mean one distance while the same change at the poles can mean another completely different distance.
I'm trying to shrink down the number of results returned by the database (in this case MySQL) so that I can calculate the distances between several points using the Great Circle formula. Instead of selecting all points and then calculating them individually I wish to select coordinates that are inside the latitude / longitude boundaries, e.g.:
SELECT * FROM poi
WHERE latitude >= 75 AND latitude <= 80
AND longitude >= 75 AND longitude <= 80;
PS: It's late and I feel that my English didn't came up as I expected, if there is something that you are unable to understand please say so and I'll fix/improve it as needed, thanks.
The length of a degree of latitude varies little, between about 110.6 km at the equator to about 111.7 near the poles. If the earth were a perfect sphere, it would be constant. For purposes like getting a list of points within say 10 km of a known (lat, lon), assuming a constant 111 km should be OK.
However it's quite a different story with longitude. It ranges from about 111.3 km at the equator, 55.8 km at 60 degrees latitude, 1.9 km at 89 degrees latitude to zero at the pole.
You asked the wrong question; you need to know the MINIMUM length to ensure that your query doesn't reject valid candidates, and unfortunately the minimum length for longitude is ZERO!
Let's say you take other folk's advice to use a constant of about 111 km for both latitude and longitude. For a 10 km query, you would use a margin of 10 / 111 = 0.09009 degrees of latitude or longitude. This is OK at the equator. However at latitude 60 (about where Stockholm is, for example) travelling east by 0.09 degrees of longitude gets you only about 5 km. In this case you are incorrectly rejecting about half of the valid answers!
Fortunately the calculations to get a better longitude bound (one that depends on the latitude of the known point) is very simple -- see this SO answer, and the article by Jan Matuschek that it references.
Originally, the definition of a nautical mile was the length of one minute of longitude on the equator. So, there were 360 * 60 = 21,600 nautical miles around the equator. Similarly, the original definition of a kilometer was that 10,000 km = length from pole to equator. Consequently, assuming a spherical earth, there would be:
40,000 ÷ 21,600 = 1.852 km per minute
1.852 × 60 = 111.11 km per degree
Allowing for a spheroidal earth instead of a spherical one will slightly adjust the factor, but not by all that much. You could be pretty confident the factor is less than 1.9 km per minute or 114 km per degree.
If you can use MySQL spatial extensions: http://dev.mysql.com/doc/refman/5.0/en/spatial-extensions.html, you can use its operators and functions both to filter the points and calculate distances. See http://dev.mysql.com/doc/refman/5.0/en/functions-that-test-spatial-relationships-between-geometries.html, specifically the functions contains() and distance().
The reference ellipsoid used for the earth is the WGS84 system, meaning
that the earth radius for the equator has the length of
6 378 137 m or 3963.19 miles
The maximum length of longitude is reached at the equator and is approximately (upper bound)
111.3195 km or
69.1708 miles
The maximum length of one degree latitude is reached between the equator and 1°. It is almost exactly equal to the maximum length of longitude; a first approximation shows that the difference is less than 4.2 meters yielding
111.3153 km or
69.1682 miles