Get places near geographical coordinates - php

I have a database filled with geographical coordinates (DB 2), like 45.062792, 8.892737 , and another that has other coordinates (DB 1).
I want to use one coordinate of DB 1 and then I want to calculate in a radius given by a user (like 10 km, 5 km, 500 mt) all the rows in DB 2 that are inside the radius previously given.
I'd like to calculate all the results without (e.g.) Google Maps or other online maps because there are limits over the usage and I want to be able to manage the results by php code on my server.

Use the Haversine formula using a lat/long coordinate and a radius as input. (I assume you have coordinates stored as separate lat and lon columns).
Your query roughly looks like this:
SELECT *, 3956 * 2 * ASIN(SQRT(POWER(SIN((#orig_lat - abs(tablename.lat)) * pi()/180 / 2),2) + COS(#orig_lat * pi()/180 ) * COS(
abs
(tablename.lat) * pi()/180) * POWER(SIN((#orig_lon – tablename.lon) * pi()/180 / 2), 2) ))
as distance
FROM tablename
HAVING distance < #radius
ORDER BY distance
LIMIT 10;
Replace #orig_lat with the given lat value and #orig_lon with the given lon value and #radius with a value in kilometers.
This will return all the coordinates from DB2 based on your coordinate from DB1 within the given radius.
More info here: http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL

Related

mysql - select records with near distance from each other

I have a mysql table containing locations, for example:
ID latitude longitude value
1 11.11111 22.22222 1
2 33.33333 44.44444 2
3 11.11112 22.22223 5
I want to select records which are located near to each other (in the above example, rows 1 and 3), so that I can insert them in a new table as one record. By saying near, let's say 100 meters. I would like the new table to be:
ID latitude longitude value
1 11.11111 22.22222 3
2 33.33333 44.44444 2
As you can see, I would like to keep the coordinates of the first record and insert an average of the two records in column 'value'.
The formula I use for distance is the following:
R*SQRT(((lon2*c-lon1*c)*cos(0.5*(lat2*c+lat1*c)))^2 + (lat2*c-lat1*c)^2)
where
[lat1, lon1] the coordinates of the first location,
[lat2, lon2] the coordinates of the second location,
[R] the average radius of Earth in meters,
[c] a number to convert degrees to radians.
The formula works well for short distances.
So, my problem is not the conversion of lat,lon to distances but my SQL. I know how to select records that have a maximum distance of 100 meters from specific lat,lon coordinates but I dont know how to select records with a maximum distance from each other.
One way I did it -and it works- is by looping the records one by one in PHP and for each one, making an SQL query to select records that are near. But this way, I do an SQL query in a loop and as far as I know, this is a bad practice, especially if the records are gonna be thousands.
I hope I was clear. If not, I would be glad to give you additional information.
Thanks for helping.
Here is a SQL to get all places within the range:
SELECT
ID,
latitude,
longitude,
(6371 * acos (cos( radians(origin.latitude)) * cos( radians( destination.latitude ))
* cos( radians(destination.longitude) - radians(origin.longitude)) + sin(radians(origin.latitude))
* sin( radians(destination.latitude)))) AS distance
FROM myTable as destination, myTable as origin
WHERE destination.id = myId
HAVING distance < 100 --some value in kilometers
6371 is a constant for kilometers.
3959 is a constant for miles.
This topic have more answers: MySQL Great Circle Distance (Haversine formula)

Querying a DB for locations in an area

I'm interested in making a site which will store several locations and needs to be able to find them based on a user's query. Similar to how sites like Yelp, Zomato, Zillow, etc. function. My preferred tech stack is PHP/MySQL.
That said, I have a few related questions. Given a database of locations with their associate latitude/longitude coordinates...
How are they able to query their database of locations and return the ones within X distance of a specific city or ZIP code?
Furthermore, how can they query their database for locations that, instead of being within proximity, are within very specific city or state limits? Where do they get their boundary data from and how do you determine if a coordinate falls within that boundary in an efficient manner?
Lastly, I notice that some of the sites have city-specific links on their site. I would have expected city data to be pulled from remote mapping APIs, but they often associate images and other content with those cities. Do these sites store the names of all cities in their own database? Where do they get their list?
This will help with your first point.
I use this query to search properties in my database by distance from a starting point. The starting point is the longitude and latitude, $coordX and $coordY. I get these from doing a geocode lookup on the Google Maps API:
SELECT properties.*,
(
( ACOS(SIN(".$coordX." * PI() / 180) *
SIN(coordX * PI() / 180) + COS(".$coordX." * PI() / 180) *
COS(coordX * PI() / 180) * COS((".$coordY." - coordY) *
PI() / 180)) * 180 / PI()) * 60 * 1.1515
)
AS distance
FROM properties
order by distance
In my table I store the coordinates of the coordinates of individual properties in the coordX and coordY columns.
Here's MySQL function that will take two latitude/longitude pairs, and give you the distance in degrees between the two points.
It uses the Haversine formula to calculate the distance. Since the Earth is not a perfect sphere, there is some error near the
poles and the equator.
To convert to miles, multiply by 3961.
To convert to kilometers, multiply by 6373.
To convert to meters, multiply by 6373000.
To convert to feet, multiply by (3961 * 5280) 20914080.
DELIMITER $$
CREATE FUNCTION haversine(
lat1 FLOAT, lon1 FLOAT,
lat2 FLOAT, lon2 FLOAT
) RETURNS float
NO SQL
DETERMINISTIC
COMMENT 'Returns the distance in degrees on the Earth between two known points of latitude and longitude. To get miles, multiply by 3961, and km by 6373'
BEGIN
RETURN DEGREES(ACOS(
COS(RADIANS(lat1)) *
COS(RADIANS(lat2)) *
COS(RADIANS(lon2) - RADIANS(lon1)) +
SIN(RADIANS(lat1)) * SIN(RADIANS(lat2))
));
END;
DELIMITER ;
Add columns to your address table for latitude and longitude with a type of FLOAT(10,6).
Write a php script to do the lookup of the lat/long when the record is saved.
Then you can do a select against the table to get a list of addresses with distances. You can even sort
the results by distance, or limit the result to a certain radius from the reference location.
SELECT
`street`,
`city`,
`state`,
`zip`,
(haversine($ref_location_lat,$ref_location_long,`lat`,`long) * 3961) as `distance`
FROM `address_table`
WHERE (haversine($ref_location_lat,$ref_location_long,`lat`,`long) * 3961) < 300 // Example for limiting returned records to a raduis of 300 miles.
ORDER BY haversine($ref_location_lat,$ref_location_long,`lat`,`long) DESC; // Don't need actual distance for sorting, just relative distance.

Get 5 rows from table

I want to fetch 5 rows from table whose "lat" value is nearest to 30. I am developing Google MAP app, where i need the 5 nearest location from Data Base.
My table looks like that,
MySQL provides a Math function that turns negative numbers into absolute values. By using that, you can get the five closest locations whether their lat is slightly lower or higher than 30:
ORDER BY ABS(lat - 30) ASC LIMIT 5
The ASC is optional as it is the default sorting order in all DBMS (thanks Gordon).
On a map "nearest location" should be based on the distance of two points, otherwise lat 30.00, long 75.00 will be the "nearest" location.
A quite exact calculation of the distance between two points (latitude/longitude) is based on the Haversine formula:
DEGREES(ACOS(COS(RADIANS(ref_latitude)) *
COS(RADIANS(latitude)) *
COS(RADIANS(ref_longitude) - RADIANS(longitude)) +
SIN(RADIANS(ref_latitude)) *
SIN(RADIANS(latitude)))) AS distance
latitude = `lat`
longitude = `long`
ref_latitude & ref_longitude = the point you want to find the nearest locations from
`DOUBLE` should be used for calculation
This results in degrees, multiply by 111.195 for an approximate distance in kilometers or by 69.093 for miles.
As you want near locations you might go for a more simple calculation using the Pythagorean theorem
sqrt(power(lat-ref_latitude, 2) +
power((lng-ref_longitude)*cos(radians(ref_latitude)), 2))
Again multiply by 111.195 for kilometers or by 69.093 for miles.
Now simply ORDER BY this distance.
And instead of comparing to all rows in your database you should restrict the number of rows to compare, e.g.
WHERE latitude BETWEEN ref_latitude - 0.2 and ref_latitude + 0.2
AND longitude BETWEEN ref_longitude - 0.2 and ref_longitude + 0.2
Btw, some DBMSes support geospatial extensions like distance functions or geospatial indexes.
As a note, if you want to do this efficiently and you have an index on lat, then the following more complex query should perform better:
select t.*
from ((select t.*
from table t
where lat <= 30
order by lat desc
limit 5
) union all
(select t.*
from table t
where lat > 30
order by lat asc
limit 5
)
) t
order by abs(lat - 30)
limit 5;
The two subqueries can use an index on lat to avoid sorting. The outer query is then only sorting 10 rows.

Using PHP and MySQL to calculate geolocation distance

I have a php script and a database of geolocations.
At the moment my users can enter their postcode, using Yahaa I get their geo location.
Now that I have their geolocation I want to write a script that loads their local businesses in order of distance. I'm guessing to do this I need to load records from the database that have the most similar coordinates to the users current geolocation. I tried this code:
$sql = "SELECT * FROM dirlistings WHERE ABS(latitude - $lat) AND ABS(longitude - $long)";
However it just displays the results in normal order.
Have I missed anything?
I think you want an ORDER clause in there somewhere.
But what you really want is the Haversine formula: MySQL Great Circle Distance (Haversine formula)
It's more complicated than you think.
This is a great article that helped me a lot. Although its written in javascript, you easily change it to php.
http://www.movable-type.co.uk/scripts/latlong.html
Note that circle distance isn't going to be precise enough if you're talking about large distances (thousands of miles, for example), as the earth's surface isn't flat. If you need a better formula for geo-distance calculation, you can use something like this:
$dlat = ((double)$lat) / 57.29577951;
$dlon = ((double)$lon) / 57.29577951;
$sql = "SELECT *
FROM dirlistings
WHERE 3963.0 * acos(sin(latitude / 57.29577951) * sin($dlat) + cos(latitude / 57.29577951) * cos($dlat) * cos($dlon - longitude / 57.29577951)) < MAX_DIST
ORDER BY acos(sin(latitude / 57.29577951) * sin($dlat) + cos(latitude / 57.29577951) * cos($dlat) * cos($dlon - longitude / 57.29577951))
";
The distances here are in miles - make sure to specify correct max distance - and this formula will give very close results for distances of even ten thousand miles. Note though that such computation is quite time- and power-intensive and if you are not dealing with large distances (i.e. nothing more than a couple hundred miles), then you should use a quicker approximation.
You've missed quite a few things. In order to do what you're trying to do, you need to compute (using the Pythagorean theorem) the distance between two points, and then order by that distance.
You can calculate distance ( (lat - $lat)^2 + (lon - $lon)^2 )^0.5 via:
SQRT(
POW(latitude - ' . $lat . ',2)
+
POW(longitude - ' . $lon . ',2)
) AS distance
Then it's as simple as:
ORDER BY distance ASC
Try ORDER BY latitude, longitude at the end. That should do it or approximately do it.

Determining if a lat-long circle and a circle on a sphere overlap

I am creating an application with Geo Proximity Search capability using PHP as server scripting language and MySQL as Databse.
Consider a situation:
Where we have certain set of objects having latitude and longitude positions assosciated with respective objects. On specifying location details like country and/or city along with range/radius in KM we are getting objects that are lying withing that radius/range using MySQL query for example:
SELECT [columns]
FROM [column]
WHERE 1=1
AND 3963.191 *
ACOS(
(SIN(PI() * [latitude] / 180) * SIN(PI() * [column].latitude / 180)) +
(COS(PI() * [latitude] /180) * cos(PI() * [column].latitude / 180) * COS(PI() * [column].longitude / 180 - PI() * [longitude] / 180)) )
<= 10
Above calculations will give the objects that are within the 10 KM area from the country/city center point on earth.
Now suppose i have one object (with latitude and longitude) which is not in this 10 KM area, but for example 15 KM from the country/city center point on earth. This object has service range 10 KM (giving service upto 10 KM area).
Now the question is if i am looking for the objects within the 10 KM range from country/city center point then the object (15 KM apart from country/city center point) having service range 10 KM should also be included in search.
How can i make it possible? I have country/city center lat, long coordinates,range/radius(in which we have to find out objects) and object having delivery radius (for e.g.10 KM) and its corresponding coordinates.
Can you guide me how to do that using PHP, MySQL?
Use MySQL spatial extensions
http://dev.mysql.com/doc/refman/5.1/en/spatial-extensions.html
On the other hand, if you want just to identify other circles that intersect with given one, they would be all of these, for which distance between centers of the circle is less then sum of radius. In other words, assuming that your original point and range is given by triple (x0,y0,r0), you need all (xn,yn,rn) for which
√((x0 - xn)² + (y0 - yn)²) ≤ r0 + rn

Categories