How to search by radius based on latitude and longitude? - c#

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.

Related

Return results depending on radius latitude and longitude

In my database I currently have all countries/states and cities, each city has its own latitude and longitude which I managed to get using reverse geocodingvia google.
When a particular user comes on to the site and says "Ok show me everyone that's in Australia, within the state of Victoria, and lives in the city of Fitzroy" within a radius of 20km I have the latitude and longitude for Fitzroy but I'm unsure on how to go about getting other users who aren't currently situated in Fitzroy but do fall in to the radius of 20km.
I did come across this thread which to me looks very promising Calculating Distance between two Latitude and Longitude, difference being I will be filtering a lot of records which could potentially be 10k if not more depending on the radius and location. I'm looking to implement a solution which not only gives me the desired results but also takes into consideration performance as well. Whether that be done in the MVC controller or in a stored procedure.
I'm wondering has anyone done something similar? Can they share their knowledge with me. I am new to this type of searching so any information/links would be beneficial.
Please note I'm not expecting you to write code for me, I'm more than capable of doing that myself.
I think, the possible solution is to calculate a range of latitude and longitude for the required city and radius. In that case, you will be able to get all users in this range using simple WHERE sql query.
For instance, you have to find all users within a radious of N km around the city with latitude = X and longitude = Y. My idea is that you should calculate min and max values of latitude and longitude which satisfy to this condition.
One degree of latitude is equal to 111.3 km. So, min and max values of latitude may be calculated this way:
minX = X - N/111.3
maxX = X + N/111.3
One degree of longitude equals to 111.3 * cos(X), so:
mixY = Y - N/(111.3 * cos(X))
maxY = Y + N/(111.3 * cos(X))
After the calculation of min and max values of latitude and longitude you will be able to compose a query to your database. It will be something like:
"SELECT FROM ... WHERE (latitude <= maxX & latitude >= minX) & (longitude <= maxY & longitude >= minY)"
I'm assuming since you're using MVC that you're using an SQL Server database. If this is the case, then you could try making use of the Spatial data support that is offered within both this and Entity Framework, rather than trying to do all the work yourself.
Try this blog post showing the basics: http://weblog.west-wind.com/posts/2012/Jun/21/Basic-Spatial-Data-with-SQL-Server-and-Entity-Framework-50

How to search (predefined) locations (Latitude/Longitude) within a Rectangular, using Sql?

I have the North, East, South and West values of a Rectangular location, how can I search only those locations (Latitude/Longitude) that are within the bounds of that Rectangular location?
Please note that I need to search the Locations (Latitude/Longitude) within a database. I need to find the locations in the database which are in the bounds of a given rectangular and I will draw markers for them on the map.
I am not talking about Google search, the APIs for search already support passing the rectangular bound to filter the search.
The googlemaps APIs can do this for me like:
var request = {
bounds: myMapObject.getBounds(), // Search only within the Bound of the Map
query: someTextToFind
};
OR
var isWithInMapsBounds = myMapObject.getBounds().contains(myLocation);
But I need to do it while getting the locations from database, I mean on Server side.
Can someone guide me in the right direction, how to achieve this functionality?
EDIT:
I want to search within database; so I need an SQL solution.
DECLARE #Bounds AS Geography = GEOMETRY::STGeomFromText('polygon-wkt-here',0)
SELECT columns-list
FROM table
WHERE 1 = #Bounds.STIntersects(table.point-column)
Quick note for those that are in the dark here about why you can't just compare your point location to the north/south/east/west coordinates of your bounding box:
The bounding box may not be lat/long-aligned (eg. its north/south/east/west lines may not follow lat/long axis).
This will happen if you draw a planar rectangle on a Lat/Long map projection. The distortion will be more apparent the closer to the edge of the bounding box the point is, and the farther from the Equator.
The second reason to use the Geography data types is that it provides a uniform method of performing these kinds of operations for ANY polygon, not just rectangles. So now you can compare if a single point is within your box, or find all the addresses in a zipcode, all with the same piece of code.
SQL Query
SELECT * FROM mytable WHERE lat >= bottomlat AND lat <= toplat AND lng >= leftlng AND lng <= rightlng
If crossing Prime Meridian or Equator you will need to modify the query
SELECT * FROM mytable WHERE lat >=bottomlat AND lat <= toplat AND lng >= leftLng AND lng < 0
UNION
SELECT * FROM mytable WHERE lat >=bottomlat AND lat <= toplat AND lng >= 0 AND lng <= rightLng

Latitude/Longitude Math Question (Distance Between Two Coordinates)

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);

Closest spatial position from Lat and Long

I have an application that uses the DotSpatial framework to connect to a usb GPS on my laptop. I essentially use it when driving out on site to know where I am.
The application also includes a ShapeFile map as background so that I know where I am.
What I have is:
I have a database with each road devided into 5m increments with a lat.long location and a road name. (So Col 1 = UniqueID, Col 2 = Location Distance in m (I.e. 0, 5, 10 ...), Col 3 = Road Name, Col 4 = Lat, Col 5 = Long)
The database is SQLite and have one that I created in Access as well.
The full DotSpatial framework
What I need to do is the following:
Work out based on my current lat/long (which I get from the GPS receiver and the GPS.NET part of the software) what the nearest Location Distance in m is from the lat/long locations in the database.
If there are any other suggestions please let me know.
P.S the application needs to be portable so dont want to mess around with SQL Server or PostgrSQL with posGIS etc.
Since you want to get the nearest distance in metres from your current lat/long, the first thing you need to do is perform a coordinate transform.
Most GPS receivers work in WGS84, and assuming this, you can use a library such as Proj4 (.NET wrapper) to convert both your current position and the road position to metres (projected coordinates; either into WGS84 projected, or a local coordinate system based on your geographic location. UTM zones can work quite well, or OSGB if you're based in the UK).
You can find a projection best suited for your needs here (however, as I write this, it's currently down... hence my lack of helpful links at this time. I will edit when it's accessible again).
If you need more help with the GIS side of this, consider paying a visit to GIS.SE
Once you have your locations in metres, get the distance between them:
double distanceX = currentXmetres - roadXmetres;
double distanceY = currentYmetres - roadYmetres;
double Distance = Math.Abs( Math.Sqrt( (distanceX * distanceX) + (distanceY * distanceY) ) );
Now you can query your database with the value of Distance and find the closest location:
SELECT * FROM table
ORDER BY ABS(Distance - Col 2)
LIMIT 1
Note: I don't know the actual name of your table, or columns, so replace "table" and "Col 2" accordingly.
You need the element in your table where the distance (pythagoras) to your point is closest.
select top 1 * from mytable
order by ( (table.lon - lon) * (table.lon - lon) + (table.lat - lat) * (table.lat - lat) )
Lon&Lat: position you're at. Skipping the sqrt will speed things up quite a bit too.

C# find all Latitude and Longitude within a mile

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

Categories