Exact distance between two points in MySQL Spatial table in KMs - php

Greetings.
I have seen a few posts and answers on this topic, but I think the result given might not be really accurate.
Let's say I have rows with different points with Longitude and Latitude, in a MySQL spatial table. I just want to retrieve the distance between them, with a simple SELECT query. I have tried:
GLENGTH(
LINESTRINGFROMWKB(
LINESTRING(
GEOMFROMTEXT(
ASTEXT(
POINTFROMWKB(
POINT( X(user_location) , Y(user_location))))),
GEOMFROMTEXT(
ASTEXT(
POINTFROMWKB(
POINT( $latitude, $longitude )))))))*100
I know its kind of 'ugly', and I'm afraid the result is not given in KiloMeters.
How am I supposed to do this? Many thanks.

Method you are using will not give you accurate results at all. Since GLENGTH uses the simple Cartesian distance formula. You can as well read in the comments here on GLENGTH's MySQL page that it cant be used on Spherical surfaces, it is there for Cartesian plane.
In this Stackoverflow answer, there is a modified formula and how to use it explained clearly, have a look at it. You will need to modify that to suit your purpose. But it will definitely guide you on how to proceed.
Hope it helps...

Related

Searching a MySQL database for values serving the input lat/long

This question is different from regular mysql lat/long, radius based data fetching
I want to search a mysql database table which contains following columns for example-
ID Items lat long serving_radius(in km)
1 Item1 26.120888 85.364723 2
2 Item2 26.120888 85.364723 5
3 Item3 25.859800 85.786598 4
4 Item4 26.594900 85.504799 8
Now if a user has lat/long (29.941095/77.812424) wants to know which of these items can be served at his location. Then how i will fetch the result using php & mysql.
I guess the SQL you are looking for is this one:
SELECT id, items, lat, long, serving_radius
FROM table
WHERE lat = 29.941095
AND long = 77.812424;
In your PHP code, you should use a DB driver (I recommend you PDO) in order to connect to the DB and execute the query.
There are plenty of tutorials about how to using PDO (creating the connection, selecting, inserting, etc).
I just found this tutorial which could help you: https://parzibyte.me/blog/en/2019/10/14/php-mysql-tutorial-using-pdo/
Edit: Not sure if you mean about how to build a query with those exact lat and long values or closer to them.
If so, you can take a look at https://gis.stackexchange.com/questions/31628/find-points-within-a-distance-using-mysql
Is "serving_radius" already stored in your table ?
What you can do is fetch distance and check if its under serving_radius
SELECT serving_radius,
(6371 * acos(cos(radians(" . $userLatitude . ")) * cos(radians(`latitude`)) * cos(radians(`longitude`) - radians(" . $userLongitude . ")) + sin(radians(" . $userLatitude . ")) * sin(radians(`latitude`)))) as distance
having distance < serving_radius
This question seems to be similar to MySQL - Find points within radius from database
Find the radius from your serving_radius and lat/lon at the database.
use the function MBRContains to find the polygon that contains the user's point.
SELECT
*
FROM
items
WHERE
MBRContains(
GeomFromText('Polygon((0 0,0 100,100 100,100 0,0 0))'),
GeomFromText('Point(77.812424 29.941095)')) = 1;
hope it helps
I think your problem is tougher than the traditional problem due to the radius being variable.
See http://mysql.rjweb.org/doc.php/find_nearest_in_mysql for discussion.
That lists 5 ways to "find the nearest X". The simplest, but slowest, is check every item for its distance. All the rest are faster because of using a "bounding-box" to limit how many items need to be checked. However, the coding gets complex.
A bounding-box, in your case, could be limited to the maximum radius in the table. Your sample data show radii of up to 8, so building a square of side 2*8 around the starting point would let you feed into the various techniques I describe.
The simplest involves INDEX(lat, lng), INDEX(lng, lat) to let the Optimizer pick which is better. The advantage is that it checks only items in a 16-wide band of latitude (or longitude), not the entire globe. The disadvantage is that it does not do much to optimize the other direction.
I suggest you use that technique as a first cut. If you need more performance then read further in my document and, optimally, come back for more help,
The techniques discussed there also allow for limiting the number of returned values.

PHP Radius Search

I'm going to build an app where the users can see points of interest in a predefined radius around their location.
My first idea was to store the latitude and longitude of all POI's in a database and comparing the users location with the POI's location via SQL.
The problem is the performance I think. If there are thousands of POI's and thousands of user requests with their location, it wouldn't be very economically or is this no problem for todays servers?
My next approach was to divide the map in quadrants, and only observing the surrounding quadrants.
tl;dr:
All in all I'm looking for:
a way to do an radius search
at best caching the results for other users
the cache will be updated when a new POI is being registered.
If you have any ideas how to realize something like that, please let me know.
Thank you
Fabian
I think what you are looking for is the Harversine formula, which it allows you to find the distance between two points in a sphere (in this case the Earth). An implementation using SQL would be something like this:
ACOS (
SIN(RADIANS($latitude)) *
SIN(RADIANS(T.latitude))+
COS(RADIANS($latitude)) *
COS(RADIANS(T.latitude))*
COS(RADIANS($longitude-T.longitud)))*6378.137 AS distance
Adding this to the select of your query will return a column called distance calculating (in Km) how far is the point ($latitude,$longitude), normally the user, from (T.latitude,T.longitude), normally the element of the table.
In case you want to filter, and don't show elements further than a certain distance you can make a condition like:
HAVING distance<$radius
I imagine that you are using MySQL, if this is the case you have to use HAVING instead of WHERE to make a condition over a computed column (distance).
A complete example of a query would be like this:
SELECT T.*, ACOS (
SIN(RADIANS($latitude)) *
SIN(RADIANS(T.latitude))+
COS(RADIANS($latitude)) *
COS(RADIANS(T.latitude))*
COS(RADIANS($longitude-T.longitud)))*6378.137 AS distance
FROM your_table as T
HAVING distance < $radius
ORDER BY distance LIMIT $limit
If you want to optimize a bit more the performance add a limit to the query so you will have for example the 10 nearest places.
Take your time to consider Spatial data types aswell since they were specificly made for this kind of work.
Note that I do not recommend you to insert your php variables directly into your query, is really unsecure, I did that only as an example.
Hope this helps you.

Include distance in search form

I would like to implement a search by distance on a website.
There must be a user in a living city can find all users living within 100 or 200 km for example.
I have a table in my database that stores all the cities and their coordinates.
I thought to create another table that would store the distance between all cities but my data base contains 36,000 cities and it may make a lot of records ...
How could I make this search more simply knowing that my project will be developed with Symfony and Doctrine?
Thank you beforehand
You can use the correct answer here to determine the distance between co-ordinates.
Measuring the distance between two coordinates in PHP
For performance reasons you need to use geospatial index to efficiently query such a database. For example MongoDB has a feature for this.
If performance is not an issue you can simply store locations in relational database table and calculate distances in SQL. See this question for some information about this solution: Geo-Search (Distance) in PHP/MySQL (Performance)

Sphinx Search Sorting/Ranking

I just recently discovered sphinx search which I want to use for my PHP application. I have a table of geolocations where every record stores a country code. For every user who uses the search function to look up geopositions, I know which country he is from.
How would I reweigh the results such that the matching results are ascending in distance to the country of the user? I already have calculated a distance matrix for each country to each other, which I can access via SQL. The country information in the geolocation database is stored as 2 letter ISO country code.
What is a good solution for this problem? I heard about UDFs, are they applicable for that problem? Is it possible to solve this problem more easily by reformatting my table?
Thank you very much.
The "easiest" way to solve this is to have coordinates for each country. You then store the coordinates for each record in the sphinx index, and when searching find the coordinates and us it in the search. This way sphinx caculates the distance dynamically.
Did you have coordinates likes this to create the matrix? But it also resupposes, you are just using a 'point' per country, if your matrix is more advanced, eg taking the closest point on the borders of each (to make disances between odd shaped countries better), then it wont work so well.
In theory you could perhaps do this with payloads, by using the country name as keywords, and the distance in a payload (arranged specially so that close disances have a high weight) but will probably be expensive to index, and might not work all that well in practice.

Determining location from Lat/Lng to match second table

I've done some reading so far and I am at a crossroads.
My situation is this:
Table with a list of lat/lng values ( we can take these to be "cities" ) with a radius
Table with a list of movement values, including a lat/lng
My requirement is that I return the list of movements and include the nearest city (if it's within the radius). I've so far used the haversine formula in PHP to do this for each record I return but it's not particularly efficient.
My two options I've found is either to:
1/ create a stored procedure in MySQL to do the Haversine that side (something like this: Proximity Search )
2/ use a "bounding box" method of positioning the cities instead of a circle. This is not a big problem and would allow the sql to be simplified. However, in some cases the typical logic of determining whether the point lies between the top left and bottom right will not work if the lat and lng are in negatives. In PHP, to work around this, I would do a quick "if" where I'd check if the top-left lat/lng is greater than the bottom-right and use AND/OR depending on the result.
After some extra reading I found this question here on SO.
https://stackoverflow.com/a/5548877/1749630
This answer was exactly what I needed to point me in the right direction. In this way I am now using a sub-select in order to find the city.
If someone posts a better answer than this one I'll mark that instead of this one :)

Categories