Latitude/Longitude Math Question (Distance Between Two Coordinates) - c#

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

Related

Calculate distance of closest point using latitude/longitude en masse?

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

How to search by radius based on latitude and longitude?

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.

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.

Mysql Haversine Procedure (radius)using a center point

I'm fairly new to MySql and what I want is to create a procedure where i can just plug in any zipcode and a distance and get back all the zipcodes within that distance. I did find a formula and tried to reshape it for what I need but I'm unable to do it. What I have is below. The example is from here http://code.google.com/apis/maps/articles/phpsqlsearch.html. However, i don't want to use 37, -122 coordinates, i want to use whichever zipcode I push into the procedure. I'd start a bounty if i could but I'd have to wait. This one has stumped me all day so any help is appreciated. This one has stumped me because i believe it uses two sets of lat/lon and i only want a radius from a central lat/lon
SELECT state,city,zipcode,
(3959
* acos(
cos(radians(37))
* cos(radians(x(location)))
* cos(radians(y(location)) - radians(-122))
+ sin(radians(37)) * sin(radians(x(location)))))
AS distance
FROM zipcodes
HAVING distance < 25
ORDER BY distance
LIMIT 0, 20;
You can approach this the same way you approach collision-detection style algorithms. Check if the coordinates are inside a bounding box by finding the minimum and maximum lat/long (given the radius) from a point, and make sure that the search meets some fast to evaluate criteria (e.g. lat <= 1.5) before running more resource intensive checks.
There is a working example with SQL and Java code here:
http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates
In summary, it says the following:
Simply combining the conditions with
AND:
SELECT * FROM Places WHERE
(Lat => 1.2393 AND Lat <= 1.5532) AND (Lon >= -1.8184 AND Lon <= 0.4221)
AND
acos(sin(1.3963) * sin(Lat) + cos(1.3963) * cos(Lat) * cos(Lon -
(-0.6981))) <= 0.1570;
Most query optimizers are smart enough
to perform an index scan to quickly
find places satisfying (Lat >= 1.2393
It then goes on to perform some additional checks. There are some alternative approaches along the same theme underneath this.
Does this help you? It looks like you have the skill to write this into a procedure yourself, but if you like I can try and write one for you. If so can you paste/post your table or an SQL batch script.

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