Given a lat and long value, is there any way of finding all lat and longs that are within a specified distance? I have a db table of lat and long values which are locations of let's say street lamps, given a lat long pair how could I find all those that are within a particular distance?
I guess drawing a circle from the starting point and finding all lat and longs contained would be the best way however, I don't have the skills to do this. I am a c# developer by trade but need a few pointers in the whole geocoding world.
You could use the Haversine Formula (see #tdammers answer) to calculate a distance between each point (Lat, Long) in your table and the given point. You will have to iterate over the entire collection in order to evaluate each point individually.
Or, if you are using SQL Server 2008, then geospatial support is built-in. Each record would store the location as a geography type (possibly in addition to two discrete columns to hold Latitude and Longitude, if it's easier to have those values broken out), and then you can construct a simple SQL query:
DECLARE #Point geography = 'POINT(-83.12345 45.12345)' -- Note: Long Lat ordering required when using WKT
SELECT *
FROM tblStreetLamps
WHERE location.STDistance(#point) < 1 * 1609.344 -- Note: 1 mile converted to meters
Another similar possibility is to bring the SQL Spatial types into your .NET application. The redistributable is found here: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=CEB4346F-657F-4D28-83F5-AAE0C5C83D52 (under Microsoft® System CLR Types for SQL Server® 2008 R2).
Then, the querying can be done via LINQ. Note: This saves you from implementing the Haversine by yourself, otherwise the process of querying would be the same.
var yourLocation = SqlGeography.Point(Latitude, Longitude, 4326);
var query = from fac in FacilityList
let distance = SqlGeography
.Point(fac.Lat, fac.Lon, 4326)
.STDistance(yourLocation)
.Value
where distance < 1 * 1609.344
orderby distance
select fac;
return query.Distinct().ToList();
The haversine formula gives you the distance (in meters; converting to miles is trivial) between two lat/lon points. From there, you can probably find the reverse...
I'm a little late for answering this, but I came up with a trick years ago to do essentially the same for satellite fields of view.
There are two points on earth where you exactly know the latitude and longitude of every point a given distance from your location. Those points are the North and South poles. So let’s put the point you want at North pole. One nautical mile away is the circle of longitudes with latitude 90 degrees minus 1 minute, or 90 – 1/60 degrees = 89.9833 degrees North latitude, since 1 minute of arc = 1 nautical mile.
Now that you have the locus of longitudes one mile from the pole with latitude 89.9833, you essentially rotate the earth until the lat/long you want is where the pole used to be. This process is called “The Rotation of the Map Graticules”. The math for this is straight forward, once you’ve thought about the equations awhile. I have them buried somewhere, so I can’t get to the code easily, however the process, with the equations is in John Snyder’s book “Map Projections: A Working Manual”. You can get the pdf free at http://pubs.usgs.gov/pp/1395/report.pdf. The explanation is on pages 29 – 32.
Chuck Gantz
some time ago I was solving a problem how to get POIs along the road. I made use of quadtree, that means dividing the whole area into cells and subcells recursively. Each POI belongs to only one cell. Having these cells you can easily do high level calculation on cell level and after that search only cells with intersection. It's more game development technique but can be used here as well. Here is something about it on Wiki:
http://en.wikipedia.org/wiki/Quadtree
Related
I'm trying to figure out, on a theoretical basis, how to find the closest points to a single point. All of these points (75,000+ points) are mapped out with latitude and longitude. The Haversine formula for distance is what I'm using to find the distance between two points, but does this formula scale on the fly?
I'm using a web front end + SQL Server backend. I can't even begin to imagine how to do this... find all distances on the fly then sort them based on distance? Again, I'm wondering if this scales to as many points as I have.
This article goes into detail about this exact subject.
The main optimization is using an index on lat/long. If you know that there must be a point within some distance of your query, you can use that known distance to only check points within that box. Because of the index, the database does a range scan.
I assume you have lat and long in an SQL database.
The best you can do with a problem like this is just to find all distances and sort them by value.
SELECT (haversine formula) as distance
FROM table
ORDER BY distance ASC
I need to convert meters to decimal degrees in C#. I read on Wikipedia that 1 decimal degree equals 111.32 km. But it is on equator, so if I'm located above/below it my the conversion will be wrong?
I assume this is wrong:
long sRad = (long.Parse(sRadTBx.Text)) / (111.32*1000);
EDIT: I need this search radius to find nearby users
long myLatitude = 100;
long myLongitude = 100;
long sRad = /* right formula to convert meters to decimal degrees*/
long begLat = myLatitude - searchRad;
long endLat = myLatitude + searchRad;
long begLong = myLongitude - searchRad;
long endLong = myLongitude + searchRad;
List<User> FoundUsers = new List<User>();
foreach (User user in db.Users)
{
// Check if the user in the database is within range
if (user.usrLat >= begLat && user.usrLat <= endLat && user.usrLong >= begLong && user.usrLong <= endLong)
{
// Add the user to the FoundUsers list
FoundUsers.Add(user);
}
}
Also from that very same Wikipedia article:
As one moves away from the equator towards a pole, however,
one degree of longitude is multiplied by
the cosine of the latitude,
decreasing the distance, approaching zero at the pole.
So this would be a function of latitude:
double GetSRad(double latitude)
{
return 111.32 * Math.Cos(latitude * (Math.PI / 180));
}
or similar.
edit: So for going the other way around, converting meters to decimal degrees, you need to do this:
double MetersToDecimalDegrees(double meters, double latitude)
{
return meters / (111.32 * 1000 * Math.Cos(latitude * (Math.PI / 180)));
}
Christopher Olsson already has a good answer, but I thought I'd fill in some of the theory too.
I've always found this webpage useful for these formulas.
A quick note on the concept
Think about the actual geometry going on.
As it stands, you are currently doing nothing more than scaling the input. Imagine the classic example of a balloon. Draw two lines on the balloon that meet at the bottom and the top. These represent lines of longitude, since they go "up and down." Quotes, of course, since there aren't really such concepts, but we can imagine. Now, if you look at each line, you'll see that they vary in distance as you go up and down their lengths. Per the original specification, they meet at the top of the balloon and the bottom, but they don't meet anywhere else. The same is true of lines of longitude. Non-Euclidean geometry tells us that lines intersect exactly twice if they intersect at all, which can be hard to conceptualize. But because of that, the distance between our lines is effectively reflected across the equator.
As you can see, the latitude greatly affects the distance between your longitudinal lines. They vary from the closest at the north and south poles, to the farthest away at the equator.
Latitudinal lines are a bit easier. They do not converge. If you're holding our theoretical balloon straight up and down, with the poles pointed straight up and straight down that is, lines of latitude will be parallel to the floor. In a more generalized sense, they will be perpendicular to the axis (a Euclidean concept) made by the poles of the longitudinal lines. Thus, the distance is constant between latitudes, regardless of your longitude.
Your implementation
Now, your implementation relies on the idea that these lines are always at a constant distance. If that was the case, you'd be able to do take a simple scaling approach, as you have. If they were, in fact, parallel in the Euclidean sense, it would be not too dissimilar to the concept of converting from miles per hour to kilometers per hour. However, the variance in distance makes this much more complicated.
The distance between longitudes at the north pole is zero, and at the equator, as your cited Wikipedia page states, it's 111.32 kilometers. Consequently, to get a truly accurate result, you must account for the latitude you're looking for. That's why this gets a little more complicated.
Getting Realistic Results
Now, the formula you want, given your recent edit, it seems that you're looking to incorporate both latitude and longitude in your assessment. Given your code example, it seems that you want to find the distance between two coordinates, and that you want it to work well at short distances. Thus, I will suggest, as the website I pointed you to at the beginning of this posts suggests, a Haversine formula. That website gives lots of good information on it, but this is the formula itself. I'm copying it directly from the site, symbols and all, to make sure I don't make any stupid typos. Thus, this is, of course, JavaScript, but you can basically just change some cases and it will run in C#.
In this, φ is latitude, λ is longitude, θ is the bearing (in radians, clockwise from north), δ is the angular distance (in radians) d/R; d being the distance travelled, R the earth’s radius
var R = 6371; // km
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;
I think the only thing that must be noted here is that R, as declared in the first line, is the radius of the earth. As the comment suggests, we're already working in kilometers so you may or may not have to change that for your implementation. It's easy enough, fortunately, to find the (average) radius of the earth in your favorite units by doing a search online.
Of course, you'll also want to note that toRadians is simply the input multiplied by Math.PI, then divided by 180. Simple enough.
Alternative
This doesn't really look relevant to your case, but I will include it. The aforementioned formula will give accurate results, but it will be at the cost of speed. Obviously, it's a pretty small deal on any individual record, but as you build up to handle more and more, this might become an issue. If it does, and if you're dealing in a fairly centralized locale, you could work off the immense nature of our planet and find numbers suitable for the distance between one degree of latitude and longitude, then treat the planet as "more or less Euclidean" (flat, that is), and use the Pythagorean Theorem to figure the values. Of course, that will become less and less accurate the further away you get from your original test site (I'd just find these numbers, personally, by asking Google Earth or a similar product). But if you're dealing with a dense cluster of users, that will be way, way, way faster than running a flurry of formulas to the Math class to work out.
Another, more abstract alternative
You might also want to think about where you're doing this logic. Here I begin to overstep my reach a bit, but if you happen to be storing your data in SQL Server, it already has some really cool geography functionality built right in that will handle distance calculations for you. Just check out the GEOGRAPHY type.
Edit
This is a response to a comment, suggesting that the desired result is really a rectangle denoting boundaries. Now, I would advise against this, because it isn't really a search "radius" as your code may suggest.
But if you do want to stick to that method, you'll be looking at two separate distances: one for latitude and one for longitude. This is also from that webpage. φ1 is myLatitude, and λ1 is myLongitude. This formula accepts a bearing and starting coordinates, then gives the resulting position.
var φ2 = Math.asin( Math.sin(φ1)*Math.cos(d/R) + Math.cos(φ1)*Math.sin(d/R)*Math.cos(brng) );
var λ2 = λ1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(φ1), Math.cos(d/R)-Math.sin(φ1)*Math.sin(φ2));
You could use that to determine the boundaries of your search rectangle.
I want to show data based on latitude and longitude with specified radius.
Example:
I have a record with latitude 55.0628 and longitude -162.3056 without specified state.
How can I show only records that within one state, using entity to linq?
If I have state Florida to show just records that within Florida.
Table Data
id item latitude longitude
1 townhome 55.0628 -162.3056
Table postal codes
id state city latitude longitude
1 alaska Akutan 54.143 -165.7854
2 Alabama Huntsville 34.7448 -86.6704
I would execute the query as close to the actual data as possible (which probably means circumventing LINQ and calling a stored procedure).
Here is a SQL user defined function that I use to calculate the distance between two locations. It leverages the new geography functionality introduced in SQL Server 2008.
CREATE FUNCTION [dbo].[GetDistanceBetween]
(
#Lat1 float,
#Long1 float,
#Lat2 float,
#Long2 float
)
RETURNS float
AS
BEGIN
DECLARE #RetVal float;
SET #RetVal = ( SELECT geography::Point(#Lat1, #Long1, 4326).STDistance(geography::Point(#Lat2, #Long2, 4326)) / 1609.344 );
RETURN #RetVal;
END
Function returns distance in miles and is very fast in my experience (this will obviously depend on how many comparisons you need to make).
You could call it using something like:
DECLARE #StartingLatitude FLOAT, #StartingLongitude FLOAT;
DECLARE #MaxDistance FLOAT = 50;
SELECT * FROM PostalCodes
WHERE dbo.GetDistanceBetween(#StartingLatitude, #StartingLongitude, latitude, longitude) <= #MaxDistance;
To know a destination is within a given larger region, you need to not just have the coordinates of a point in the larger region, but coordinates that map out it's entire boundary.
If you have this data, it becomes a matter of the Point in Polygon problem. I've found that ray-tracing was quite easy to implement in both SQL and C# so a nice one to have as a function that you make Linq-aware, though I only did it Linq2SQL not Linq2Entities.
If you only have the co-ordinates of central points, you can find the closest such point, using STDistance. This could though, easily mis-identify a location near the border of a larger state as being in the smaller state, because it is is close to the centre of the smaller state than the larger.
If you do go with that, but you aren't using SQL 2008 (so no STDistance) you can get a crude approximation by ordering on ((lat1 - lat2) * (lat1 - lat2)) + ((lng1 - lng2) * (lng1 - lng2)). This gives the relative distance as if the world really were a rectangle like the Mercator projection suggests. The inaccuracy gets worse the further the points are from the equator, so it might be just about tolerable for US states, but fail with Canadian provinces.
The proper and fastest way is to start with your lat-lon pair of a zip code and find the East, West, North and South points for a given distance (radius). Follow this link for the relative formulas. Then use these points to get zip codes from the database; something like:
select *
from zipcodes
where
lat >= South
and lat <= North
and lon >= West
and lon <= East
-- and state = 'FL' -- use it optionally
Now having all zip records within the square defined by East, North, West and South points (as lines) proceed with distance calculations (use Tim's code) and keep only the records within the radius. (If all points in the square where records, then something like 22% would be out of the radius).
Obviously if you use CTE you will perform the whole sql thing with only one query.
I currently have a database query that calculate the distance between every store in the database from there to a "home" location. I'm calculating the flight distance using this formula.
http://www.movable-type.co.uk/scripts/latlong.html
Then I'm ordering them and displaying them. I discovered a much better way to do it is only search for stores whose latitude/longitude are within a range.
For example instead of calculating distance between each store in the database (over 30000), only group ones with lat/longs within a certain range and calculate distance between those.
Right now I'm trying to found out how to calculate the actual bounds. The distance has to be below 5km. So I divide 5 by 100 and cap the latitude and longitude by those amounts.
SELECT storeid, storedescription, address, city, storebannerdescription, lat, lon,
ROUND (gc_dist (lat, lon, 43.758152, -79.746639), 1) AS distance
FROM storelatlon
WHERE ((lat-43.758152) < 0.05 AND (lat -43.758152) > -0.05) AND ( (lon-(-79.746639)) < 0.05 AND (lon-(-79.746639)) > -0.05)
ORDER BY Distance
This method could work, but depending on how widely distributed your stores are, you may need to refine your bounds a bit because as you go up in latitute, you cross more longitude over a given distance. You may get too many or too few points just filtering by 0.05 deg for all latitudes.
I assume that you are using PostgreSQL based on your use of gc_dist. As long as you have PostGIS installed, then you can perform the desired logic using built-in functionality.
You will have to prepare your table for this:
First, store your location as a PostGIS point. I suggest using WGS-84 for geographic calculations.
After you do that, then you can query for all points within any given distance from your desired location using ST_Contains and ST_Buffer, where ST_Buffer wraps the center point that you want to find neighbors for (-79.746639, 43.758152) in long/lat order.
I have never used PostgreSQL for this, but I have done this with Oracle. It appears to take the same setup for PostgreSQL as it did for Oracle:
A. Tell the database that you will be creating a geometric-based column. Found syntax here.
SELECT AddGeometryColumn('db_name', 'table_name', 'desired_column_name', 4326,
'POINT', 2);
Above, 4326 is a constant "SRID" denoting WGS-84.
B. Add an index to the column. Found syntax here (this page seems very useful).
CREATE INDEX desired_index_name
ON table_name
USING gist(desired_column_name);
C. Add your data.
INSERT INTO table_name (desired_column_name)
VALUES('SRID=4326;POINT(-79.746639 43.758152)');
(I am curious if the above string needs to be contained by ST_GeomFromText based on other examples)
or (I found here)
INSERT INTO table_name (desired_column_name)
VALUES (ST_Transform(ST_MakePoint(-79.746639, 43.758152), 4326));
Note: I assume it's (X, Y), which means Longitude and Latitude ordering.
D. Query your data.
SELECT * FROM table_name
WHERE
ST_Contains(
ST_Buffer(
ST_Transform(ST_MakePoint(-79.746639, 43.758152), 4326),
distance_probably_in_meters),
desired_column_name);
I'm currently trying to reverse geocode a series of lat/long co-ordinates using the Virtual Earth/Bing Maps web services. Whilst I can successfully retrieve an address for the positions I also need to be able to retrieve the closest significant population centre for the position so I can display a heading and distance to the centre of the nearest town/city/metropolis etc. This is for cases where the location is travelling between locations e.g. on a highway/motorway.
Has anyone out there got any ideas how to do this as I've been banging my head against it for a few days now and I've gotten nowhere!
Cheers in advance...
I think it is safe to assume that the nearest city is always quite close compared with the size of the Earth, so you can use a simple pythagoras triangle.
Suppose you are at (lat0, long0) and a trial city is at (lat1, long1).
Horizontal (EW) distance is roughly
d_ew = (long1 - long0) * cos(lat0)
This is multiplied by cos(lat0) to account for longitude lines getting closer together at high latitude.
Vertical (NS) distance is easier
d_ns = (lat1 - lat0)
So the distance between the two points is
d = sqrt(d_ew * d_ew + d_ns * d_ns)
You can refine this method for more exacting tasks, but this should be good enough for the nearest city.
For comparing distances, it will be fine to compare d squared, which means you can omit the sqrt operation.
try using the wikipedia location service, documented here
http://www.geonames.org/export/wikipedia-webservice.html
It sounds like you're looking for a database of latitudes and longitudes of major cities, so you can calculate distances.
This is a link to a page giving a few dozen, world-wide.
There may be others, most likely US-centric (but that may be what you want).
I would do the following:
table 1:
T_CityPopulation
Fields:
CityTownInfo,Population,LonLat
Then compute distance between your current LonLat for each record in table 1, using a threshold value ignore towns/citys over x miles. Then sort the results by Population.
EDIT:
Even if you don't want to maintain a table, it has to be stored somewhere, I think if you maintained it yourself at least you have control over it, vs relying on another service.