Calculating the centroid from points in a MySQL-table - mysql

In a MySQL-table I have a column of the "point" geospatial datatype. Is it posssible to calculate the centroid of all the point-values of all rows directly in MySQL?
The aim of my project is to put the center of a map at the centroid of the points that it contains.
One potential solution is given in the MySQL documentation: Centroid(mpoly). But this would mean that I had to concatenate all points' values externally in a programming language and then send the resulting query back to MySQL. This sounds quirky to me.

A centroid is simply the intersection of the mean X and Y values, so the following should work:
SELECT
POINT( AVG(X(geographic_location)), AVG(Y(geographic_location)) )
FROM poles

Related

Storing vector coordinates in MySQL

I am creating a database to track the (normalized) coordinates of events within a coordinate system. Think: a basketball shot chart, where coordinates of shot attempts are stored relative to where they were taken on the basketball court, in both positive and negative directions from center court.
I'm not exactly sure the best way to store this information in a database in order to give myself the most flexibility in utilizing the data. My options are:
Store a JSON object in a TEXT/CHAR column with X and Y properties
Store each X and Y coordinate in two DECIMAL columns
Use MySQL's spatial POINT object to store the coordinate
My goal is to store a normalized vector2 (as a percentage of the bounding box), so I can map the positions back out onto a rectangle of any size.
It would be nice to be able to do calculations, like distance from another point, but my understanding of spatial objects is that it is more for geographical coordinates than a normalized vector. The other options, however, make calculations a bit more difficult though, currently for my project, they aren't a definitive requirement.
Is it possible to use spatial POINT for this and would calculations be similar to that of measuring geographical points?
It is possible to use POINT, but it may be more of a hassle retrieving or modifying the values as it is stored in binary form. You won't be able to view or modify the field directly; you would use an SQL statement to get the components or create a new POINT to replace the old one.
They are stored as numbers and you can do normal mathematical operations on them. Geospatial-type calculations on distance would use other geospatial data types such as LINESTRING.
To insert a point you would have to create a point from two numbers (I think for your case, there would be no issues with the size of the numbers) :
INSERT INTO coordinatetable(testpoint) VALUES (GeomFromText('POINT(-100473882.33 2133151132.13)'));
INSERT INTO coordinatetable(testpoint) VALUES (GeomFromText('POINT(0.3 -0.213318973)'));
To retrieve it you would have to select the X and Y value separately
SELECT X(testpoint), Y(testpoint) from coordinatetable;
For your case, I would go with storing X and Y coordinate in two DECIMAL columns. It's easier to retrieve, modify and having X and Y coordinates separate would allow you direct access to to the coordinates rather than extract the values you want from data stored in a single field. For larger data sets, it may speed up your queries.
For example:
Whether the player is past half court only requires Y-coordinate
How much help the player could possibly get from the backboard would rely more on the X-coordinate than the Y-coordinate (X closer to zero => Straighter shot)
Whether the player usually scores from locations close to the long edges of the court would rely more on the X-coordinate than the Y-coordinate (X approaches 1 or -1)

Is there any MySQL function to directly get 5 closest coordinates to a given coordinate from database?

I am working with PHP and use MySQL for database. I need a way, to get 5 closest coordinates to a given coordinate from database, which is very fast and at least 80-90% accurate. I have researched a lot. I found havershine formula, spherical law of cosines, bounding square method to compare min and max latitude-longitude values with coordinate in database and other methods which use trigonometric math functions. But all these formulas take a long to return result in database with thousands of entries. Does MySQL provide any function to do it fast?
See this similar question on the GIS Stack site. The performance of your ultimate solution will depend on how many targets are in the reference table you are searching and if you can limit the distance you are interested in (such as closest 5 within 30 miles). I don't think you can reliably optimize the process; you need to calculate the distance for all coordinates in your reference table.

Return records in chronological order, given a separation factor

I have a massive table in SQLServer 2008, it contains the position reported by technicians every minute. I need to report on this table but in order to control the amount of records that are displayed in the report both a time and distance separation factors need to be taken into account.
So, a query may look like
"Return all records with no less than 5 minutes and/or 300 feet between them".
The time part is done, but I'm having a hard time with the distance factor. I have the latitude and longitude for each point, and I have no problem if I need to include a SQLServer 2008 spatial UDT in order to resolve the problem.
Things I have considered:
Bring the records by the time factor, and apply the separation constrain in the client by calculating the distance between adjacent points and discard those which falls inside the the factor. (the easiest, but it must be the one consuming more resources).
Keep the last record per technician in a cache, pre-calculate the distance between the record and its predecessor, and resolve the constrain in the client. (should consume less resources than 1) since the distance is pre-calculated, however and since the table is BIG It will increase the size of the dataset, not sure if the space is worth the processing savings).
Use the spatial functions in SQLServer 2008, but honestly I had been reading and I couldn't find anything that helps me resolve this type of requirement. Any GIS expert??
I would like to go with the best option possible (maybe not listed above?) and IMO should be the one using the SQLserver features most efficiently.
What Raciel is asking, is how to "simplify" a list of points by a distance's factor. Suppose you have a list of one hundred spatial points sorted by dateTime, and the distance between one point from the previous is exactly 150 feets, he need to get just the list of points which distance is 300 feet, the result set should be a list of around 50 points...
I just imagine do this using a cursor.
The formula is:
3949.99 * arcos(sin(LAT1) * sin(LAT2) + cos(LAT1) * cos(LAT2) * cos(LONG1 - LONG2))
The radius of Earth is 3949.99 miles. All rest is self explanatory. This formula is Great Circle distance calculation formula.
Prior to SQL 2008, the most common solution was to use a UDF to calculate the great-circle distance between two points on a sphere. The Haversine formula is probably the most commonly used method.
Of course the Earth is not actually a perfect sphere, but this was considered "good enough" for most uses.
In SQL 2008, as you anticipated, such calculations are simplified and made more accurate by the introduction of the Geography and Geometry data types. Here's a brief sample of how you can use them to simplify distance calculations.
DECLARE #locations TABLE(locname VARCHAR(100), coord geography)
DECLARE #loc1 geography
DECLARE #loc2 geography
INSERT INTO #locations
VALUES('HOME', geography::Point(-81.810194, 41.478156, 4326)) --Note: Lat, Long, SRID
--The 4326 is the SRID (spatial reference id) used by SQL as
--a reference to the WGS 84 Standard. This is the same reference
--used by the GPS system
INSERT INTO #locations
VALUES('WORK', geography::Point(-81.687771, 41.498227, 4326))
SELECT * FROM #locations
SELECT #loc1 = coord FROM #locations WHERE locname = 'HOME'
SELECT #loc2 = coord FROM #locations WHERE locname = 'WORK'
SELECT #loc1.STDistance(#loc2) * 3.2808399 --STDistance is in meters so we multiply to convert to feet
The SRID is the key to the improved accuracy. The WGS 84 specification to which it refers includes a standardized coordinate system and a reference ellipsoid. In other words, it accounts for the non-spherical nature of the Earth, giving better results than a pure spherical Great Circle calculation.
If GIS accuracy is important to your work, this is the simplest way to implement it in SQL 2008.

How to use MySQL geospatial extensions with spherical geometries

I would like to store thousands of latitude/longitude points in a MySQL db. I was successful at setting up the tables and adding the data using the geospatial extensions where the column 'coord' is a Point(lat, lng).
Problem:
I want to quickly find the 'N' closest entries to latitude 'X' degrees and longitude 'Y' degrees. Since the Distance() function has not yet been implemented, I used GLength() function to calculate the distance between (X,Y) and each of the entries, sorting by ascending distance, and limiting to 'N' results. The problem is that this is not calculating shortest distance with spherical geometry. Which means if Y = 179.9 degrees, the list of closest entries will only include longitudes of starting at 179.9 and decreasing even though closer entries exist with longitudes increasing from -179.9.
How does one typically handle the discontinuity in longitude when working with spherical geometries in databases? There has to be an easy solution to this, but I must just be searching for the wrong thing because I have not found anything helpful.
Should I just forget the GLength() function and create my own function for calculating angular separation? If I do this, will it still be fast and take advantage of the geospatial extensions?
Thanks!
josh
UPDATE:
This is exactly what I am describing above. However, it is only for SQL Server. Apparently SQL Server has a Geometry and Geography datatypes. The geography does exactly what I need. Is there something similar in MySQL?
How does one typically handle the discontinuity in longitude when working with spherical geometries in databases?
Not many people use MySQL for this, because it's geospatial extensions aren't really up to snuff.
From the docs:
"All calculations are done assuming Euclidean (planar) geometry."
The solution is usually to roll your own.
Alternatively, you can fake it -- if your distances are less than a 500 miles or so, then you can treat your latitude and longitude as rectangular coordinates and just use the euclidean distance formula (sqrt(a^2 + b^2)).

Get polygons close to a lat,long in MySQL

Does anyone know of a way to fetch all polygons in a MySQL db within a given distance from a point? The actual distance is not that important since it's calculated for each found polygon later, but it would be a huge optimization to just do that calculation for the polygons that are "close".
I've looked at the MBR and contains functions but the problem is that some of the polygons are not contained within a bounding box drawn around the point since they are very big, but some of their vertices are still close.
Any suggestions?
A slow version (without spatial indexes):
SELECT *
FROM mytable
WHERE MBRIntersects(mypolygon, LineString(Point(#X - #distance, #Y - #distance), Point(#X + #distance, #Y + #distance))
To make use of the spatial indexes, you need to denormalize your table so that each polygon vertex is stored in its own record.
Then create the SPATIAL INDEX on the field which contains the coordinates of the vertices and just issue this query:
SELECT DISTINCT polygon_id
FROM vertices
WHERE MBRContains(vertex, LineString(Point(#X - #distance, #Y - #distance), Point(#X + #distance, #Y + #distance))
The things will be much more easy if you store UTM coordinates in your database rather than latitude and longitude.
I don't think there's a single answer to this. It's generally a question of how to organize your data so that it makes use of the spacial locality inherent to your problem.
The first idea that pops into my head would be to use a grid, assign each point to a square, and check select the square the point is in, and those around it. If we're talking infinite grids, then use a hash-value of the square, this would give you more points than needed (where you have collisions), but will still reduce the amount by a bunch. Of course this isn't immediately applicable to polygons, it's just a brainstorm. A possible approach that might yield too many collisions would be to OR all hashed values together and select all entries where the hashes ANDed with that value is non-zero (not sure if this is possible in MySQL), you might want to use a large amount of bits though.
The problem with this approach is, assuming we're talking spherical coordinates (lat, long generally does) are the singularities, as the grid 'squares' grow narrower as you approach the poles. The easy approach to this is... don't put any points close to the poles... :)
Create a bounding box for all of the polygons and (optionally storing these results in the database will make this a lot faster for complex polygons). You can then compare the bounding box for each polygon with the one round the point at the desired size. Select all the polygons which have intersecting bounding boxes.