i have a table with two fields (X,Y)
they hold the location of points in New Israel Projection (EPSG: 2039) (e.g. X=194545.05941493041, Y=668112.83849507652)
i want to reproject all points to WGS84 (EPSG: 4326). (e.g. the same coordinates above should translate to something around: 34.940578289586, 32.106153057749005
how do i do that in SQL 2008?
There may be a easier solution now, but what I had to do a few years ago was the following:
I needed to reproject between UTM33N(x, y ) and WGS84 (lat lon).
I use http://projnet.codeplex.com/ to translate each coordinate. The key you need is the two WKT (WellKnownText) that make up the projection model.
For me it was some hours of try and fail, but eventually I had a good translation.
Later when we started to use spatial indexes I created a SSIS package to reproject all data on inport.
There may be better solutions that that today:
perhaps it's supported by http://sqlspatialtools.codeplex.com/
Also I see that many are using ogr2ogr http://www.gdal.org/ogr2ogr.html
Related
MYSQL ver 5.7
Requirement:
I have a bunch of POINT geometries in MYSQL table and I have to find all the POINT geometries that are within 5km distance/radius of a GEOMETRYCOLLECTION object.
GEOMETRYCOLLECTION may contain more than one type of geometries like POINT, POLYGON etc.
Sample GEOMETRYCOLLECTION data:
SET #g1 = ST_GeomFromText('GEOMETRYCOLLECTION(POINT (-156.366489591715 66.913750389327),POLYGON ((-156.357608905242 66.906958164897, -156.360302383363 66.9066027336476, -156.361997104194 66.9067073607308, -156.363616093774 66.9066368440642, -156.365477697938 66.9065867326059, -156.368127298976 66.9065970034393, -156.370061891681 66.9066888794808, -156.37182258022 66.9068547305222, -156.373286981259 66.9070724523969, -156.374390675008 66.9072952721882, -156.376359777088 66.9077681138541, -156.377706173961 66.9080113180204, -156.379222192708 66.9081328753119, -156.380729601039 66.9081591586452, -156.382562289578 66.9081211961453, -156.387571662487 66.9099676951007, -156.389320598943 66.9125180930134, -156.389291120818 66.9145787836353, -156.384722634367 66.9167899596735, -156.37955035 66.9195246586276, -156.372520662511 66.9209119638337, -156.360432280238 66.9215118034161, -156.355776993787 66.9203754471679, -156.34906598338 66.9180659711298, -156.347941981299 66.9174007836309, -156.346853913592 66.9167568252985, -156.34605399901 66.9158971169665, -156.346982815675 66.9151925950926, -156.346794497967 66.9144321773854, -156.345642955261 66.9140107294695, -156.343831364638 66.9136152003034, -156.342996512556 66.9130307378043, -156.343113243806 66.9123137492637, -156.343498096931 66.9119029992644, -156.344661664637 66.9111819440571, -156.345080786511 66.9105884961414, -156.345524286511 66.9099605023924, -156.347168040675 66.9098486503092, -156.348952756297 66.9096090419763, -156.348689200048 66.9089614565606, -156.349495732338 66.908706844061, -156.350786711503 66.9082992794783, -156.352211271917 66.9083472388533, -156.353952768789 66.90829894302, -156.355389368787 66.9082072242701, -156.356512531285 66.9079768284371, -156.356677961493 66.9078075857291, -156.356422527119 66.907644261771, -156.355901372953 66.9072802273965, -156.357608905242 66.906958164897)))');
Sample POINT data:
SET #p1 = ST_GeomFromText('GEOMETRYCOLLECTION(POINT (-156.342840017 66.9320439348))');
I have tried ST_DISTANCE_SPHERE(#g1,#p1) spatial function (which returns the value in meters) but it seems it doesn't support geometry types other than POINT and MULTIPOINT.
Then I have used:
ST_DISTANCE(#g1,#p1)
'0.015301834064271899'
I am unable to understand the what is the UNIT of this returned value in MYSQL 5.7?
I have searched a lot on the internet and there is no proper documentation available regarding the same. In POSTGIS, this can be done but I am struggling to do this in MYSQL ver 5.7.
Any help is appreciated.
Thanks in advance!
ST_Distance returns "distance" in degrees here - i.e. the flat map view of the shortest distance between shapes. This value cannot be mapped to real distance, as real world distance of 1 degree along parallel is different from distance of 1 degree along meridian except near the equator.
Looks like MySQL cannot correctly compute distance here. You would be better served by systems with more geospatial support, like PostgreSQL + PostGIS, or Google BigQuery, etc. They give you correct answer, you just need to replace ST_GeomFromText with ST_GeogFromText to work with spherical geographies.
I am just starting to learn PostgreSQL and PostGIS in particular and I try to follow the Penn State University Intro into Spatial Database Management when I decided to play around a little with the basic data I got. After calculating the length for some LINESTRING data I wanted to check the results using QGIS and thats where the fun started.
Here you can find the SQL Statements I followed and altered a little bit.
https://www.e-education.psu.edu/spatialdb/node/1960
When comparing the results in the attribute table I was confused because the results differed using the ST_Length vs. QGIS Field Calculator´s $Length function despite specifying the same SRID (2163).
INSERT INTO lines (name, geom)
VALUES ('Holland Tunnel',ST_GeomFromText('LINESTRING(
-74.036486 40.730121,
-74.03125 40.72882,
-74.011123 40.725958)',4269)),
('Lincoln Tunnel',ST_GeomFromText('LINESTRING(
-74.019921 40.767119,
-74.002841 40.759773)',4269)),
('Brooklyn Bridge',ST_GeomFromText('LINESTRING(
-73.99945 40.708231,
-73.9937 40.703676)',4269));
UPDATE TABLE lines SET laenge = ST_Length(ST_Transform(geom, 2163));
The Results are:
Order:
A. ST_Length for Holland Tunnel; Lincoln Tunnel; Brooklyn Bridge
B. $Length for Holland Tunnel; Lincoln Tunnel; Brooklyn Bridge
A. 2160,344849130080092; 1631,543481596899937; 694,591179476468028
B. 2195,119177785873489; 1656,890881978494235; 701,411239204245931
If I made an obvious mistake I´m really sorry but the suggestions within StackOverflow didn´t point me to the right direction scince they were on the subject of distances based on routing which doesn´t apply here right?
Best regards and thank you in advance!
using:
UPDATE lines SET laenge = ST_Length(geom::geography);
I can reproduce the Qgis results you posted, that means Qgis is not using the projection you specified to compute the length of the lines
You can read more in qgis about $length:
The length calculated by this function respects both the current
project's ellipsoid setting and distance unit settings. For example,
if an ellipsoid has been set for the project then the calculated
length will be ellipsoidal, and if no ellipsoid is set then the
calculated length will be planimetric.
and about the difference between geometry and geography in:
postgis docs
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.
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
I found that some result of MBRContains(g1,g2) and other functions seems not right to me.
and I want to find out why. how to see the mbr?
The Envelope function is what you're looking for to get the MBR for an arbitrary Geometry. See: http://dev.mysql.com/doc/refman/5.5/en/gis-general-property-functions.html#function_envelope
could this be why:
http://forums.mysql.com/read.php?23,271928,271968
minimum bounding rectangles for a geometry always have edges parallel to the coordinate axes.
You can just construct them youself with min & max, too.
I agree with Steve0 PostGIS is the way to go...... or you could use the Java Topology Suite (JTS).. or Net Topology Suite (NTS) version... and use datastores such as the very common GIS format of Shapefiles rather than a full db. Guess it depends what you're doing.
As fastmultiplication said MBRs are parallel to coord axes... however you can also use the rotating caliper approach to find minimum bounding boxes which are aligned to the longest axis line of the shape... if you need that.
Check here for more info:
http://cgm.cs.mcgill.ca/~orm/rotcal.html
And in general - MySQL is not the database to use for spatial operations. Most of the spatial functions are not really implemented. I would reccomend PostGIS on Postgresql for a spatial FOSS db. You could also look at spatiallite, built on SQLIte