I'm working on a MYSQL/PHP system where I have the following:
-- a set of latitude, longitude in the form of (lat,lng) stored as text format : (lat1,lng1)#(lat2,lng2)#(lat3,lng3) etc. which is basically a polygon drawn over a googlemap instance stored in the database.
-- a table which stores in a field - a point's coordinates P(plat,plng) which is basically a point where a device is stationed
I need to figure out how many polygons from the first table are within a distance of X kilometers from the point P essentially using MYSQL.
I have come across quite a few Google Map libraries regarding this already, but I intend to resolve this by the quickest method possible - which I assume is via a MYSQL query.
Can anyone please please shed some light regarding this?
I've so far consulted a few examples on geospatial querying - and come up with this :
SELECT user_id, latitude, longitude,
GeomFromText( "POINT(CONCAT_WS(' ',latitude,longitude))" ) AS point,
Contains( GeomFromText( 'POLYGON(-26.167918065075458 28.10680389404297,
- 26.187020810321858 28.091354370117188, -26.199805575765794 28.125,-26.181937320958628 28.150405883789062, -26.160676690299308 28.13220977783203, -26.167918065075458 28.10680389404297)' ) ,
GEOMFromText( "POINT(CONCAT_WS(' ',latitude,longitude))" ) )
FROM user_location
But the problem is it shows a record with lat: -26.136230, long: 28.338850 as well which is way off the polygon's boundaries. Can anyone please guide?
I'm not sure if you want to calculate the distance to the nearest corner of the polygon, boundary of the polygon or some notional central point of it. Either way I think the mathmetical solution to this is to use Pythagoras' theorem to work out the proximity of points.
If you have lat1,lng1 and lat2,lng2 expressed in metres I believe that the distance between them is:
SQRT(POW(ABS(lat1 - lat2),2) + POW(ABS(lng1 - lng2),2))
Using an algorithm similar to this you need to decide whether you want to compare your known lat/lng to a single central point of the polygon or to the points of its corners (three times the work!).
MySQL does have a geospatial extension which could be worth looking at. Unfortunately I don't have experience of it.
Okay, did this - and it works - might help someone:
SELECT user_id,latitude,longitude,
Contains(
PolyFromText( 'POLYGON((-26.167918065075458 28.10680389404297, -26.187020810321858 28.091354370117188, -26.199805575765794 28.125,-26.181937320958628 28.150405883789062, -26.160676690299308 28.13220977783203, -26.167918065075458 28.10680389404297))' ),
PointFromText(concat("POINT(",latitude," ",longitude,")"))
) as contains
FROM user_location
=====
Although I agree on expert's views that PostGIS could be a better option.
Related
In my database I have polygons stored. Now I need to search all the polygons that are within a certain radius.
Even if the polygon is only a small part inside the region, then it should be included inside the results (so once there is a minimal match, there is a match).
What is the best way to do this? I have been thinking about creating another polygon and search everything that intersects this, but don't know if this is a valid method?
Yes, I think it is the best approach. You can create a polygon using ST_BUFFER and then you can use ST_INTERSECT to find if polygons will intersect your polygon.
May be you can also do it using ST_DISTANCE. It will calculate minimum distance of a point from polygon.
Select ST_DISTANCE(polygons,POINT(x, y)) as distance, polygon_id from your_polygon_table WHERE distance <= 10
I struggled with the same issue and came up with the following that works well.
select this.poly, other.poly
from table this, table other
where this.name = 'name of subject polygon'
and ST_Distance(ST_Centroid(this.polygon),ST_Centroid(other.polygon)) < 'desired distance';
This will work with the initial point is in the same table as the other polygons. If you have a fixed initial point you can simplify the query as follows:
select poly from table
where ST_Distance('26.36, -81.07',ST_Centroid(other.polygon)) < 'desired distance';
Normally to find polygons that compasses a certain GPS point you can use a query like:
SELECT * FROM `polygons` WHERE ST_CONTAINS(`polygon`, POINT(-33.874087, 151.207865)));
However how you go with this if you would want to give the GPS point a certain margin in degrees? The only way i can currently think of is creating a MySQL function that does a loop that goes through every lat/long combination till it hits the margin and finally returns the polygons that it found. I'm however hoping there's a more efficient way to do this. I'm happy to do this in MySQL or PostgreSQL. Example input for finding compassing polygons:
latitude = 33.8275
longitude = 151.2695
latitude_span = 0.0216
longitude_span =0.0437
You can create a Buffer around the point to represent a circle, and check if it intersect the polygon. It appears to exist in both psql and mysql, but I can't find any documentation for mysql.
select polygon
from polygons
where ST_Intersects(polygon, ST_Buffer(ST_GeomFromText('POINT(100 90)'), degrees));
I have the following latitude and longitude:
lat - 18.9802767
lng - 72.8142511
I am trying the following query for places withint 10 kms from the point of interest.
select mbrcontains( geomfromtext(
'LINESTRING(72.8993663648088 19.0702857,72.72913583519122 18.8902677)'
),
geomfromtext(
'point(18.9802767 72.8142511)'
) );
The Linestring geometry object is derived from the exact point that I am trying to determine is within using the method for mysql 5.1 and above from this example using the formula :
linestring(point(#lng+10/(111.1/cos(radians(#lat))),#lat+10/111.1), point(#lng-10/(111.1/cos(radians(#lat))),#lat-10/111.1))
From what I understand the point falls within the Minimum Bounding Rectangle (MBR). However the query returns a 0 for the answer. The above is following the principles given in this example.
What is wrong with the query? How can I know if the point is within a certain geospatial distance (in this case the MBR points are calculated using 10 kms from the point given by co-ordinates: lat - 18.9802767, lng - 72.8142511).
BTW, I am using MySQL 5.5.32.
Your point does not fall within the MBR of the line. Looks like you've reversed the latitude or longitude coordinates on either the line or the point. Switch the X and Y in 'point(18.9802767 72.8142511)' to get this point, which will be within the MBR of the line:
POINT (72.8142511 18.9802767)
If you are tied to MySQL, you may consider updating to MySQL 5.6, then using the Buffer function to create a circular area from your point of interest, and then use ST_Within to find anything within that circular area.
If you are not tied to MySQL, consider PostGIS, which provides a nice ST_DWithin function that makes these comparisons very easy.
My question is somewhat related to this similar one, which links to a pretty complex solution - but what I want to understand is the result of this:
Using a Mysql Geometry field to store a small polygon I duly ran
select AREA(myPolygon) where id =1
over it, and got an value like 2.345. So can anyone tell me, just what does that number represent seeing as the stored values were long/lat sets describing the polygon?
FYI, the areas I am working on are relatively small (car parks and the like) and the area does not have to be exact - I will not be concerned about the curvature of the earth.
2.345 of what? Thanks, this is bugging me.
The short answer is that the units for your area calculation are basically meaningless ([deg lat diff] * [deg lon diff]). Even though the curvature of the earth wouldn't come into play for the area calculation (since your areas are "small"), it does come into play for the calculation of distance between the lat/lon polygon coordinates.
Since a degree of longitude is different based on the distance from the equator (http://en.wikipedia.org/wiki/Longitude#Degree_length), there really is no direct conversion of your area into m^2 or km^2. It is dependent on the distance north/south of the equator.
If you always have rectangular polygons, you could just store the opposite corner coordinates and calculate area using something like this: PHP Library: Calculate a bounding box for a given lat/lng location
The most "correct" thing to do would be to store your polygons using X-Y (meters) coordinates (perhaps UTM using the WGS-84 ellipsoid), which can be calculated from lat/lon using various libraries like the following for Java: Java, convert lat/lon to UTM. You could then continue to use the MySQL AREA() function.
Tech used: MySQL 5.1 and PHP 5.3
I am just designing a new database for a site I am writing. I am looking at the best way of now storing Lat and Lng values.
In the past I have been using DECIMAL and using a PHP/MySQL select in the form:
SQRT(POW(69.1 * (fld_lat - ( $lat )), 2) + POW(69.1 * (($lon) - fld_lon) * COS(fld_lat / 57.3 ), 2 )) AS distance
to find nearest matching places.
Starting to read up more on new technologies I am wondering if I should use Spatial Extensions. http://dev.mysql.com/doc/refman/5.1/en/geometry-property-functions.html
Information is quite thin on the ground though and had a question on how to store the data. Instead of using DECIMAL, would I now use POINT as a Datatype?
Also, once stored as a POINT is it easy just to get the Lat Lng values from it in case I want to plot it on a map or should I additionally store the lat lngs as DECIMALS again as well?
I know I should prob use PostGIS as most posts on here say I just don't want to learn a new DB though!
Follow up
I have been playing with the new POINT type. I have been able to add Lat Lng values using the following:
INSERT INTO spatialTable (placeName, geoPoint) VALUES( "London School of Economics", GeomFromText( 'POINT(51.514 -0.1167)' ));
I can then get the Lat and Lng values back from the Db using:
SELECT X(geoPoint), Y(geoPoint) FROM spatialTable;
This all looks good, however the calculation for distance is the bit I need to solve. Apparently MySQL has a place-holder for a distance function but won't be released for a while. In a few posts I have found I need to do something like the below, however I think my code is slightly wrong:
SELECT
placeName,
ROUND(GLength(
LineStringFromWKB(
LineString(
geoPoint,
GeomFromText('POINT(52.5177, -0.0968)')
)
)
))
AS distance
FROM spatialTable
ORDER BY distance ASC;
In this example geoPoint is a POINT entered into the DB using the INSERT above.
GeomFromText('POINT(52.5177, -0.0968)' is a Lat Lng value I want to calculate a distance from.
More Follow-up
Rather stupidly I had just put in the ROUND part of the SQL without really thinking. Taking this out gives me:
SELECT
placeName,
(GLength(
LineStringFromWKB(
LineString(
geoPoint,
GeomFromText('POINT(51.5177 -0.0968)')
)
)
))
AS distance
FROM spatialTable
ORDER BY distance ASC
Which seems to give me the correct distances I need.
I suppose the only thing currently that needs answering is any thoughts on whether I am just making life difficult for myself by using Spatial now or future-proofing myself...
I think you should always use the highest level abstraction easily available. If your data is geospatial, then use geospatial objects.
But be careful. Mysql is the worst geospatial database there is. Its OK for points but all its polygon functions are completely broken - they change the polygon to its bounding rectangle and then do the answer on that.
The worst example that hit me is that if you have a polygon representing Japan and you ask what places are in Japan, Vladivostok gets into the list!
Oracle and PostGIS don't have this problem. I expect MSSQL doesn't and any Java database using JTS as its engine doesn't. Geospatial Good. MySQL Geospatial Bad.
Just read here How do you use MySQL spatial queries to find all records in X radius? that its fixed in 5.6.1.
Hoorah!
Mysql GIS yagni:
If you have no experience with GIS, learning spatial extensions is practically like learning a new database, plus a little math, and a lot of acronyms. Maps, projections, srids, formats... Do you have to learn all that to calculate distances between points given a certain lat/long: probably not, will you be integrating 3rd party GIS data or working with anything more complex than points, what coordinate system will you be using?
Going back to yagni: do things as simple as posible, in this case implement your code in php or with simple SQL. Once you reach a barrier and decide you need spatial, read up on GIS system, coordinate systems, projects, and conventions.
By then, you will probably want PostGIS.
It's a good thing, because then you get to use spatial indexes on your queries. Limit to a bounding box, for example, to limit how many rows to compare against.
If you can affor placing some extra code into your backend, use Geohash.
It encodes a coordinate into a string in a way that prefixes denote a broader area. The longer your string is, the more precision you have.
And it has bindings for many languages.
http://en.wikipedia.org/wiki/Geohash
https://www.elastic.co/guide/en/elasticsearch/guide/current/geohashes.html