Mysql Distance from test point to a polygon - mysql

I have stored some map zones to a table using Geometry type field.
So the inserts are like this:
INSERT INTO zones (zoneName, coords) VALUES ('name',
PolygonFromText('POLYGON((
41.11396418691335 1.2562662363052368,
41.11370552595821 1.2560248374938965,
41.11851079510035 1.2459397315979004,
41.11880984984478 1.2461864948272705,
41.11396418691335 1.2562662363052368))'));
Then I have the user position, and I need to know if he is inside some zone. This works well with this:
SELECT id
FROM zones
WHERE MBRContains(coords,GeomFromText('POINT(41.117783 1.260590)'))
But sometimes, user position is not perfect, so I think its better to know wich zone is closest to user position.
That is the part that I don't have any idea about... I found some queries to get distance between two points, but not a point and polygons.

The MBR series of functions (like MBRContains) are unsuitable for what you're trying to do; they only test bounding rectangle inclusion.
You may wish to jump forward to MySQL 5.6.1, and use the ST_ functions, like ST_Contains. These functions actually test the geometry.
The problem you're working on can be defined as an uncertainty in the position of your POINT when you go to compare it to your collection of boundary POLYGON items.
Try this: create a POLYGON from your point that is a square with the size of your uncertainty. You can think of this square as a "fuzzy" point. (You could also use an octagon or another closer approximation of a circle in place of a rectangle, but your querying speed will slow.)
Then use ST_Within to see if you have a unique polygon that entirely contains your fuzzy point. If you get just one polygon, you're done.
If you get multiple polygons that entirely contain your fuzzy point, that means some of your boundary polygons overlap other ones. You need to figure out what this means in your problem space. If your data is intended to be properly structured cartographic boundary data, it means you have a data mistake. (NOTE: This is not unheard of :-)
If you get no polygons that entirely contain your fuzzy point, then your fuzzy point may or may not overlap the boundary of at least one polygon. Use ST_Overlaps to find those polygons.
If you get just one, you're done -- your fuzzy point is near the boundary of just one polygon.
If you get none, you're done -- your fuzzy point is away from the boundaries of all your polygons.
If you get more than one hit, you have an ambiguity -- your fuzzy point is near the boundary of more than one polygon.
This is the hard case to sort out. You could reduce the size of the fuzzy point and try again. This MIGHT yield just one polygon result. But, you could deceive yourself into thinking that your points are more accurate than they are by doing this.
MySQL doesn't have the geometric operator Area(Intersection(Polygon, FuzzyPoint)). If it did you could choose the polygon with the biggest area of intersection with your fuzzy point, and that would be a good disambiguator. But it would still be as inaccurate as the position of your point.
Maybe your application should handle the category of result "too near the boundary of A, B, and C to be sure."

Related

How do I find the region a point lies within

Below I have an image representation of a map with different regions labeled on it.
My problem is that I need to find out what region a randomly generated point on the map will be in.
I know the x_min, y_min, x_max, y_max of all the different regions meaning I have the coordinates for all the vertices of each rectangular region. I also know the coordinate of the point.
What you can do, and what I have done, is just go through a big condition statement checking through one by one if the x & y coordinate of the point is between the x_min and x_max and y_min and y_max of every region. However, I feel like there has to be a more scalable, generalizable, and efficient way to do this. I however cannot find a way to do so, at least not something that isn't in a library for a different programming language. I thought of maybe doing something where I split the map in half, find out which half the point lies in, count up all the regions in that half, check if there is one region left and if not, split the map in half again and go through the process again. I just don't have a good idea of how that can be implemented and whether that is feasible or better that the current method I have.

trying to see if a point is within 50ft of a linestring

I have a database with a bunch of LineString's and I want to see if a Point is within, say, 50ft of that line.
Since it's a LineString, expecting ST_CONTAINS to return true for a point that's even 1ft away from the LineString seems unlikely BUT if there was a way to add an accepted error margin that'd be cool.
Here's the query I did:
SELECT *
FROM railroads
WHERE ST_CONTAINS(SHAPE, ST_GeomFromText('POINT(-10874300.116373 3537642.0497826)', 3857));
Unsurprisingly, it returns no results.
Any ideas? I'm running MySQL 8.0.22.
You need a condition like
ST_Distance(shape, geo_constant) < distance.
Another pattern to do it is
ST_Intersect(shape, ST_Buffer(geo_constant, distance)).
Buffer is expensive, so make sure you buffer a single constant, not the table column.
But there is another issue here, you are using projection 3857, so the distance is in projection units, not feet or meters. If you care about precision, transform Geometry to Geography type.

GPS coordinations for each kilometer

I'll find a route between two places, for example using google maps. I'd like to divide the route to kilometers (two following places will be at a distance of 1 km), and get GPS coordinations of these places. This is because then I'll be able to get exacly the coordinations of, for example, 5th kilometer on the route. Could you please advice me how to achieve it?
This is extremely nontrivial. Is say your best bet is to find an algorithm to load the bearing between two points, then one to load a coordinate given a start point, distance, and bearing. This could give you it, but only if the data contained only straight lines. Since I assume the Google Maps API only gives you the turns the user has to make, this approach will be inaccurate when there are bends in roads. You'd need GIS data for roads and what will undoubtedly turn into a complicated algorithm to find something like this. It's definitely doable, but that's l how I'd start. Look into the Census TIGER road data, it should help.
Unless, of course, I'm wrong and the API does actually give enough points to cleanly map it, in which case those functions should be easy to find and implement.
This will only work if you have the polyline as a sequence of lat/lon (or other) coordinates, wherever you get that from.
Then you start at the beginning an iterate through the lines (point[i], point[i+1]).
THis distance you calculate with standard API.
while itersting you sum up the distance.
Once you exceed the 1000m, you know that the splitting point (the 1000m marker) is at line segment [i,i+1].
To calculate the exact position where on the line that is, you take the total summed meters from previous segment, and the value of this segment and do a linear interpolation.
The working code is a bit complexer: there can be multiple markes within one segement.
But first find out where you get the polyline from, whitou that it will not work.

MBR Within not accurate in mysql

I have been using the MBRWithin function for quite a lot of times. Suddenly I notice on google map this POINT(101.11857 4.34475) is out of the geo fence which I specify but it still give a value of 1 in mysql any reason or tweaking need to be done?
SELECT MBRWithin(GeomFromText('POINT(101.11857 4.34475)'),GeomFromText('POLYGON((101.12112522125244 4.3531723687957164,101.11846446990967 4.351417913665312,101.13138198852539 4.336397898951581,101.13477230072021 4.33211863778494,101.14065170288086 4.321933898868271,101.14992141723633 4.306699328215635,101.15455627441406 4.30978050198082,101.1397933959961 4.334600612212089,101.12112522125244 4.3531723687957164,101.12112522125244 4.3531723687957164))')) As geoFenceStatus
MySQL 5.6.1 and later have exact geometry algorithms in addition to the earlier functions that only operated on MBR.
You can use ST_WITHIN rather than MBR_WITHIN. See documentation. Like this
SELECT ST_Within(GeomFromText('POINT(101.11857 4.34475)'),
GeomFromText('POLYGON((101.12112522125244 4.3531723687957164,101.11846446990967
4.351417913665312,101.13138198852539 4.336397898951581,101.13477230072021
4.33211863778494,101.14065170288086 4.321933898868271,101.14992141723633
4.306699328215635,101.15455627441406 4.30978050198082,101.1397933959961
4.334600612212089,101.12112522125244 4.3531723687957164,101.12112522125244
4.3531723687957164))')) As geoFenceStatus
MBRWithin() will return results based on the minimum bounding rectangle of it's parameters. Your polygon contains both larger and smaller values for both coordinates than the point, so it will be within the polygon's MBR.
MySQL has no built-in point in polygon algorithm, so you'll either have to roll your own or find one elsewhere. This one seems to be a good candidate.

Mysql geometry AREA() function returns what exactly when coords are long/lat?

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.