What units does DbGeometry.Distance return? - mysql

MSDN documentation just defines the return value as:
A double value that specifies the distance between the two closest
points in this geometry value and other.
What units are returned? When testing the values do not match to anything I recognise and does not work in a WHERE clause.
var results = db.Locations.Where(t => t.ItemPoint.Distance(targetPoint) <= 100); // 100km
Note: I am using MySQL with Entity Framework using the .NET Connector, which doesn't support using SRID values.

Whilst the MSDN documentation could do with a little more information, it doesn't specify the measurement of the value as it changes dependant on the SRID (or lack thereof).
Without an SRID, Geometry simply works on a flat grid (or planar) system (think old school square paper). Your distance answers are therefore simple pythagoras results of
a2 + b2 = c2 >>>>>> c = SqRt(a2 + b2).
For example:
using System.Data.Entity.Spatial;
DbGeometry geom1 = DbGeometry.FromText("POINT(0 0)");
DbGeometry geom2 = DbGeometry.FromText("POINT(50 50)");
Console.WriteLine(geom1.Distance(geom2));
//Returns 70.71067811 (the square root of (50 sq'd + 50 sq'd)).
You'll find this blog an interesting read, skip to halfway down the page and you'll find how to create a user-defined haversine calculation method which will allow you to convert the results to distances.
Be warned though, If you can't map Stored Procedures in EF for MySQL, then you'll need to resort to good old fashioned ADO to get the results. Make sure you use st_distance over mbr_distance as st_distance will be exact and mbr_distance will contain false positives. You will need MySQL 5.6.1 for st_distance.
Lastly, if at all possible, consider another database if Spatial data is important.

Related

how to find float values in mysql database with rails

Let's say I have a rails model called Position and the two columns latitude and longitude (both defined as float). I have populated the model with some position values. Now I'm trying to find positions based on it's latitude:
positions = Position.where('positions.latitude = ?', 50.0)
returns nil.
Even if I try this:
lat = Position.first.latitude
positions = Position.where('positions.latitude = ?', lat)
the result is nil. My database is mysql for production. The code above words in development (sqlite). My assumption is it has something to do with how the datatypes are handled but I dont get it. Anyone some ideas?
Don't use FLOAT or DOUBLE when you need exact numeric values.
Read https://dev.mysql.com/doc/refman/8.0/en/problems-with-float.html
Instead, use DECIMAL or NUMERIC (they're synonyms).
See How accurately should I store latitude and longitude? for some guidance on the specific DECIMAL precision to use for latitude and longitude.
This is maybe due to how floating point numbers are represented. It's not possible to compare them by using a normal equality comparison. Instead of checking for the exact match it's better to check if the number is in a range or round both numbers to some precision before comparing them.
Regarding the particular example with geographical coordinates (I assume this because latitude is used), I would recommend using decimal column type instead of float.
In case you would like to stick with floatcolumn, I can suggest checking if the value is in a range.

Check if a point is near a linestring with MySQL Spatial Extension (untrustable)

I have to discover if a given point is at least 500 meters (ou other distance) from a route line that exist in my database recorded using the MySQL Spatial.
I see there is no similar function in MySQL Spatial, and find a previous answer that doesn't work for me because the line is too big (more than 300km) to check with this solution point by point:
Find N Nearest LineString From A Point Using MySQL Spatial Extensions
I'm even can't create a buffer (a circle/polygon with a given radius) to the point to check if is even touch.
UPDATE - 12/7
I did it, but MySQL Spatial it is seams not trustable.
I made a createBuffer function, to create a 20 points Polygon around the given Point with a meters given distance for the radius: http://pastebin.com/xEFb8ZXi
I'm testing with the QGis the given results from this buffer, and everything is fine with the function (except the meters to decimal degress value that generate smaller then expected, but it is not the issue right now).
And made a few Intersects checks, and this is aways return true, even if the result polygon is not intersects the line.
I remade the same tests using just the center point, and the results is the same.
I discovery now that the INTERSECT doesn't check the LineString with the Point or Polygon, but the Bounding Box of the LineString, when a indicate a point OUTSIDE the Linestring BBox.
Intersects QUERY Where "rota" is the Linestring data:
SELECT Intersects(rota, createBuffer(GeomFromText('POINT(-19.7736 -43.7255)'),500))
FROM log_viagem WHERE rota IS NOT NULL;
How can I trust the MySQL Spatial now?
Or my concept about INTERSECTS is wrong?
SOLVED:
I didn't read the important note at 5.5 version of MySQL:
Note
Currently, MySQL does not implement these functions according to the specification. Those that are implemented return the same result as the corresponding MBR-based functions.
The Solution is taking with the server administrator to update to 5.6.1, there is an upgrade in the note
Note
MySQL originally implemented these functions such that they used
object bounding rectangles and returned the same result as the
corresponding MBR-based functions. As of MySQL 5.6.1, corresponding
versions are available that use precise object shapes. These versions
are named with an ST_ prefix. For example, Contains() uses object
bounding rectangles, whereas ST_Contains() uses object shapes.
As of MySQL 5.6.1, there are also ST_ aliases for existing spatial
functions that were already exact. For example, ST_IsEmpty() is an
alias for IsEmpty()

Where is MySQL's the POINT() function documented?

It seems like besides using WKT and the GeomFromText function, MySQL support an other method of creating geometries. The function POINT() is used in the examples in the documentation, but I can not find where the function itself is documented.
This one is pretty straightforward, but I wonder if there are any other functions which can be used as well, instead of parsing WKT strings.
MySQL has a spacial data type POINT. It's a type that encapsulates an x and y value pair to represent a coordinate in some space.
You can create a table with a column of that type via:
CREATE TABLE my_table (pt POINT);
For every spacial type there's a "constructor" function(s) to create a value of that type. For example, Point(x,y) - it returns a value of type POINT to be stored in the db, used in another function, etc:
INSERT INTO my_table (pt) VALUES (Point(1,2));
The docs that cover the functions for creating values of these types (incl. the Point() function) can be found at Creating spacial values and the section of the manual that it's in covers spacial types in general.
POINT is not a function, it's a data type.
You use it like POINT(100, 20) to give you a coordinate of x = 100, y = 20.
It is documented at 12.16.2.3 Class Point:
A Point is a geometry that represents a single location in coordinate space.
Point Examples
Imagine a large-scale map of the world with many cities. A Point object could represent each city.
On a city map, a Point object could represent a bus stop.
This is where MySQL documents Point class.
A Point is a geometry that represents a single location in coordinate space.
It is documented here under title 12.16.5 MySQL-Specific Functions That Create Geometry Values
If you need to understand this constructor function and other information on Spatial Type in MySQL, follow my article on Medium Playing with Geometry/Spatial Data Types in MySQL

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.

On-the-fly parser/pre-generation space/time tradeoff considerations

Do the space-related benefits of using an on-the-fly parser outweigh the time-related benefits of a pre-generated lookup table?
Long version:
I am authoring a chemistry reference tool, and am including a feature that will automatically name formulae conforming to a specific pattern; e.g. C[n]H[2n+2] => [n]ane; where [n] is an integer for the LHS; and an index into an array of names on the RHS. (meth, eth, …)
As far as I can see, this can be implemented in one of two ways:
I pre-generate a key/value dual lookup dictionary of formula <=> name pairs; either when the application starts (slower startup), or a static list which is published with the application (slower download).
Formulae are evaluated on the fly by a custom-built parser.
In approach 1. name => formula lookup becomes simpler by an order of magnitude; but the generator will, unless I want to ship dozens of megabytes of data with the application, have to have a preset, and fairly low, value for n.
Compounding this is the fact that formulae can have several terms; such as C[n]H[2n+1]OC[n']H[2n'+1]; and for each of these, the number of possible matches increases geometrically with n. Additionally, using this approach would eat RAM like nobody's business.
Approach 2. lets me support fairly large values of n using a fairly small lookup table, but makes name => formula lookup somewhat more complex. Compared to the pre-generation to file for shipping with the application, it also lets me correct errors in the generation logic without having to ship new data files.
This also requires that each formula be matched against a cursory test for several rules, determining if it could fit; which, if there are a lot of rules, takes time that might lead to noticeable slowdowns in the interface.
The question then, is:
Are there any considerations in the tradeoff I have failed to account for, or approaches that I haven't considered?
Do the benefits of using an on-the-fly parser justify the increased implementation complexity?
You should go with the second approach.
One possible solution is a greedy algorithm. Define your set of transformations as a regular expression (used to test the pattern) and a function which is given the regexp match object and returns the transformed string.
Regular expressions aren't quite powerful enough to handle what you want directly. Instead you'll have to do something like:
m = re.match(r"C\[(\d+)\]H\[(\d+)]\]", formula)
if m:
C_count, H_count = int(m.group(1)), int(m.group(2))
match_size = len(m.group(0))
if C_count*2+2 == H_count:
replacement = alkane_lookup[C_count]
elif C_count*2 == H_count:
replacement = alkene_lookup[C_count]
...
else:
replacement = m.group(0) # no replacement available
(plus a lot more for the other possibilities)
then embed that in a loop which looks like:
formula = "...."
new_formula = ""
while formula:
match_size, replacement = find_replacement(formula)
new_formula += replacement
formula = formula[match_size:]
(You'll need to handle the case where nothing matches. One possible way is to include a list of all possible elements at the end of find_replacement(), which only returns the next element and counts.)
This is a greedy algorithm, which doesn't guarantee the smallest solution. That's more complicated, but since chemists themselves have different ideas of the right form, I wouldn't worry so much about it.