GeomFromText function documentation - mysql

I see that the following syntax is used in examples:
GeomFromText('Polygon((1 1, 2 2, 3 3))');
The double parenthesis caused a bit of a trouble so I decided to look it up in the official documentation. At my non-small surprise the search mysql polygon did not give me the documentation of this function. A search to mysql geomfromtext also did not give the definition of the function GeomFromText.
So I'm still looking for the official documentation of these functions.

I see that the MySQL Reference Manual for GeomFromText() doesn't even give a typical function definition either, but it does describe how to use it. GeomFromText() converts from "well-known text" (abbreviated as WKT) to MySQL's internal format. WKT is simply a textual representation of a geometry object, which can be a polygon as your example, or any of the other geometry types. A key point to understand is that Polygon(...) is the WKT format for a polygon; it isn't a MySQL function call, even though it sort of looks like one.
Polygons can contain holes. When defining a polygon, you may optionally supply one or more interior boundaries to define such holes. The WKT for polygons use inner parentheses to distinguish these boundaries from one other. Even if you don't want to define holes, the inner parentheses are still required. Wikipedia provides some simple examples of polygon WKTs together with pictures of the resulting polygons.

Related

MySQL ERROR 3037: Invalid GIS data provided to function st_within

Following query:
SELECT st_contains(ST_GeomFromText('POLYGON((
9.2949170148074 3.5550157117451,
12.230624391667 3.5550157117451,
12.24455565975 4.9035765788215,
9.300807190941 4.8942904468525,
9.3019824958588 3.5550157117451,
9.2949170148074 3.5550157117451
))'),ST_GeomFromText("POINT( 6.31 8.92)"))
issues error Invalid GIS data provided to function st_within.
Although I don't see anything wrong with the query (last point is the same as first, points create ring, syntax is correct). When I remove the second to last point (9.3019824958588 3.5550157117451) then the query succeeds:
SELECT st_contains(ST_GeomFromText('POLYGON((
9.2949170148074 3.5550157117451,
12.230624391667 3.5550157117451,
12.24455565975 4.9035765788215,
9.300807190941 4.8942904468525,
9.2949170148074 3.5550157117451))'),ST_GeomFromText("POINT( 6.31 8.92)"))
Did I miss something?
Can I somehow further debug the message about Invalid GIS data to be more useful?
I'm using MySQL 5.7.31-0ubuntu0.18.04.1
I believe I found the answer: I tried ST_IsValid on both polygons, first one returned false (probably because it intersects itself), second one true. However, I tried several other self-intersecting polygons to feed the st_contains function without raising an error.
Then according to https://dev.mysql.com/doc/refman/5.7/en/geometry-well-formedness-validity.html
Spatial computations may detect some cases of invalid geometries and raise an error, but they may also return an undefined result without detecting the invalidity.
So whenever I got some result using self-intersecting polygons in the past, it was undefined and only this particular polygon in this question raised an error.
Conclusion is that if one uses spatial functions, one should check validity of geometry beforehand using ST_IsValid, because MySQL does not check it on inserts, nor updates - according to documentation:
It is permitted to insert, select, and update geometrically invalid geometries, but they must be syntactically well-formed. Due to the computational expense, MySQL does not check explicitly for geometric validity.
One point to add, this functionality has apparently changed between MySQL 5.6 and 5.7, in 5.6 the "faulty" polygon does not raise an error, whereas in 5.7 does.

How would you define a keyword beyond the fact that it is reserved.

My question is Python specific (3.4.3).
My question is specific to Built-In functions only.
It is clear to me the difference between a keyword (reserved word) and an identifier (user-defined variable).
See: https://en.wikipedia.org/wiki/Reserved_word
Likewise, I understand the basic meaning of the terminology 'function'
See : https://en.wikipedia.org/wiki/Functional_programming \
and
http://www.learnpython.org/en/Functions
However, I am having difficulty understanding the difference between Built-in functions and keywords; such as 'if' and 'for'.
https://docs.python.org/3/library/functions.html#built-in-funcs
What is the difference between the two? Keyword and Function.
Is the Keyword 'if' not simply a built in function? If so, why does it not appear in the official list of Built-In functions in the Python documentation?
https://docs.python.org/3/library/functions.html#built-in-funcs
It certainly behaves as a function. Is it simply because it preforms a procedure as opposed to returning a value? In which case how would you define it? As a method?
I have searched high and low on stackoverflow and I cannot seem to locate an answer.
Answers such as the two examples given below do not answer the overriding questions for me. Which are;
1) What defines a keyword as a keyword, rather than a builtIn function?
2) If keywords such as 'if' are not functions, then what are they? They are not classes etc. I understand that 'IF' is an example of a condition statement but what is the generic terminology for these keywords. The word keyword only defines the fact that it is reserved within the language, it does not define what the actual object is, i.e. function, class, method etc.
http://stackoverflow.com/questions/6054672/whats-the-difference-between-a-keyword-or-a-statement-and-a-function-call
http://stackoverflow.com/questions/155609/difference-between-a-method-and-a-function?rq=1
Keywords are those that describe the action to be performed, or specify how to interpret something (give meaning to instructions)
Functions are simply labels (for a set of instructions).
If you change function names it won't matter to Python (you can edit built in modules), but you can't relabel keywords.
You have already added tons of references to both, so I will not cite more.

MySQL: Spatial Query to find whether a latitude/longitude point is located within a given boundary

I'm working on google map search functionality. The vision of this is to find whether a (geolocation) point is located within a polygon or not as shown in the illustration below?
I'm using mysql 5.6.20 with Spatial extension, I know it has useful geometry functions built-in, so I will be allowed to query geocoded locations from a database directly.
My aim was to familiarize myself with geospatial functions, so I wrote up an experimental sql.
given a point geolocation: POINT(100.52438735961914 13.748889613522605)
and a polygon or boundary to be tested with was:
POLYGON(100.49503326416016 13.766897133254545,100.55940628051758 13.746555203977,100.56266784667969 13.72170897580617,100.48885345458984 13.739051587150175)
here is my sql example:
SELECT ST_Within(
ST_GEOMFROMTEXT('POINT(100.52438735961914 13.748889613522605)'),
ST_GEOMFROMTEXT('POLYGON(100.49503326416016 13.766897133254545,
100.55940628051758 13.746555203977,100.56266784667969 13.72170897580617,
100.48885345458984 13.739051587150175)'))
As geoFenceStatus
but after issuing the command, what I got in return seemed to be as follows:
geoFenceStatus
===============
null
I'm so unsure why it returned me 'null' value. since it was indicated in function documentation that this should return '1' in case a point resides within a given polygon
any advice would be appreciated, how to get my sql right.
The error message isn't very clear but your issue is that you have an invalid Polygon. There are two problems with it:
You have to repeat the first point at the end -- this is to differentiate it from a LINESTRING, essentially, ie, it is closed.
POLYGONS start with and end with double parenthesis, ie, POLYGON((x1 y1, x2 y2.......xn yn, x1 y1)). This is to allow for inner rings to be delineated with single parenthesis sets inside the polygon.
See the wikipedia WKT article for more information.
You should find that if you write you query as:
SELECT ST_Within(ST_GEOMFROMTEXT('POINT(100.52438735961914 13.748889613522605)'),
ST_GEOMFROMTEXT('POLYGON((100.49503326416016 13.766897133254545, 100.55940628051758 13.746555203977,100.56266784667969 13.72170897580617, 100.48885345458984 13.739051587150175,
100.49503326416016 13.766897133254545))'))
As geoFenceStatus
then is should work.

Saving and restoring geometries in OpenLayers

Context: I'm a just-hours-old newbie at OpenLayers, please be gentle.
Fundamentally, I have a map with some drawn objects on it. If I understand things correctly, I have a number of OpenLayer.Feature.Vector (layers?) with a number of OpenLayer.Geometry "things" (like LinearRing) on it.
At the moment, I seem to be able to get a nice representation of the geometry, using .toString(). Yes, I suspect I'm doing it wrong -- feel free to point me in the right direction.
This yields a very human readable, and database storable, strings such as:
POINT(-104.74560546875 44.2841796875)
POLYGON((-96.52783203125 44.6796875,-96.52783203125 45.734375,-92.22119140625 45.734375,-92.22119140625 44.6796875,-96.52783203125 44.6796875))
LINESTRING(-105.71240234375 44.6796875,-106.06396484375 42.658203125,-103.55908203125 42.7021484375,-103.47119140625 45.55859375,-104.65771484375 45.20703125)
Is there an inverse way of getting these back into the object format from whence they came?
I'd love to be using JSON, but can't seem to get GeoJSON to accept my OpenLayer.Feature.Vector object (which is what the CLASS_NAME property says it is when I peer inside).
Many thanks.
The Openlayers.Geometry objects’ toString method converts them nicely to WKT (Well-Known Text). If you use a GIS layer on top of your database (like PostGIS for PostGres, SQL Spatial for SQL Server, Spatialite for SQLite, etc.), they should offer functions that enable you to process WKT.
But if you want to convert that WKT to a new Openlayers.Geometry object (in the browser), you can use the fromWKT function:
var point = OpenLayers.Geometry.fromWKT('POINT(-104.74560546875 44.2841796875)');
alert(point.toString()); // POINT(-104.74560546875 44.2841796875)
Here, the variable point will now contain a new Openlayers.Geometry object, which has the same properties as the original one you used toString() on.
If you pass an array to the fromWKT function, it will return a GeometryCollection containing all the generated geometries.
var geometryTexts = [
'POINT(-104.74560546875 44.2841796875)'
, 'POLYGON((-96.52783203125 44.6796875,-96.52783203125 45.734375,-92.22119140625 45.734375,-92.22119140625 44.6796875,-96.52783203125 44.6796875))'
, 'LINESTRING(-105.71240234375 44.6796875,-106.06396484375 42.658203125,-103.55908203125 42.7021484375,-103.47119140625 45.55859375,-104.65771484375 45.20703125)'
],
collection = OpenLayers.Geometry.fromWKT(geometryTexts);
After this, collection.toString() should yield the following:
GEOMETRYCOLLECTION(POINT(-104.74560546875 44.2841796875),POLYGON((-96.52783203125 44.6796875,-96.52783203125 45.734375,-92.22119140625 45.734375,-92.22119140625 44.6796875,-96.52783203125 44.6796875)),LINESTRING(-105.71240234375 44.6796875,-106.06396484375 42.658203125,-103.55908203125 42.7021484375,-103.47119140625 45.55859375,-104.65771484375 45.20703125))
In my other answer, I went with WKT because you mentioned it. I now see that you seem to prefer GeoJSON.
To convert a vector layer or an Openlayers.Geometry object to a GeoJSON string, you should use the OpenLayers.Format.GeoJSON.write function:
var geoJSON = new OpenLayers.Format.GeoJSON(),
geoJSONText = geoJSON.write(geometryObject);
Note that you should be able to pass your object to this function, since (according to documentation) it accepts an OpenLayers.Feature.Vector as well as a OpenLayers.Geometry or an array of features.
Conversely, when you’ve got a GeoJSON string, you can convert that back to an object using the OpenLayers.Format.GeoJSON.read function:
var geometry = geoJSON.read(geoJSONText, 'Geometry');
The second parameter lets you indicate which type of object you’d like returned. Read the docs linked to for more information.
Also, take a look at this demo for a more extensive example. (View the source of the page to see how they’re doing it).

How do you know what SRID to use for a shp file?

I am trying to put a SHP file into my PostGIS database, the the data is just a little off. I think this is because I am using the wrong SRID. The contents of the PRJ file are as follows:
GEOGCS["GCS_North_American_1983",
DATUM["D_North_American_1983",
SPHEROID["GRS_1980",6378137.0,298.257222101]],
PRIMEM["Greenwich",0.0],
UNIT["Degree",0.0174532925199433]]
What SRID does this correlate to? And more generally, how can I look up the SRID based on the information found in the PRJ file? Is there a lookup table somewhere that lists all SRID's and their 'geogcs' equivalents?
The data imported using srid=4269 and 4326 were the exact same results.
Does this mean I'm using the wrong SRID, or is this just expected margin of error?
The shp file is from here.
To elaborate on synecdoche's answer, the SRID is sometimes called an "EPSG" code. The SRID/EPSG code is a defacto short-hand for the Well-Known-Text representations of projections.
You can do a quick search on the SRID table to see if you can find an exact or similar match:
SELECT srid, srtext, proj4text FROM spatial_ref_sys WHERE srtext ILIKE '%BLAH%'
Above was found at http://www.bostongis.com/?content_name=postgis_tut01.
You can also search on spatialreference.org for these kinds of things. The search tool is primitive so you may have to use a Google search and specify the site, but any results will show you the ESRI PRJ contents, the PostGIS SQL INSERT, and a bunch of other representations.
I think your PRJ is at: http://spatialreference.org/ref/sr-org/15/
Prj2EPSG is a small website aimed at exactly this problem; paste in the PRJ contents and it does its best to find a matching EPSG. They also have a web service API. It's not an exact science. They seem to use Lucene and the EPSG database to do text searches for matches.
The data seems to be NAD83, which has an SRID of 4269. Your PostGIS database has a spatial_ref_sys table which is the SRID lookup table.
If the data looks the same with an SRID of 4269 (NAD83) and 4326 (WGS84), then there's something wrong.
Go and download the GDAL utilities , the ogrinfo (which would spit the projection information) and ogr2ogr utilities are invaluable.
James gave already a link to spatialreference.org. That helps to find spatial reference information... I assume you did load the spatial_ref_sys.sql when you prepared your postgis instance.
And to be honest, I don't think the problem is in the PostGIS side of things.
I usually keep my data in different SRIDs in my PostGIS dbs. However, I always need to project to the output SRS. You are showing OpenStreetMap pre-rendered tiles, and I bet they have been drawn using SRID 900913 (the Google Map's modified mercator projection that now everyone uses to render).
My recommendation to you is:
1- Set the right projection in the OpenLayers code which matches whatever tiles you are reading from.
2.- Keep the data in the database in whatever SRID you want (as long as it is correct of course).
3.- Make sure the server you are using to generate the images from your data (ArcGIS Server, Mapserver, GeoServer or whatever it is) is reprojecting to that same SRS.
Everything will match.
Cheers
Use GDAL's OSR Python module to determine the code:
from osgeo import osr
srsWkt = '''GEOGCS["GCS_North_American_1983",
DATUM["D_North_American_1983",
SPHEROID["GRS_1980",6378137.0,298.257222101]],
PRIMEM["Greenwich",0.0],
UNIT["Degree",0.0174532925199433]]'''
# Load in the projection WKT
sr = osr.SpatialReference(srsWkt)
# Try to determine the EPSG/SRID code
res = sr.AutoIdentifyEPSG()
if res == 0: # success
print('SRID=' + sr.GetAuthorityCode(None))
# SRID=4269
else:
print('Could not determine SRID')
Be sure to take a look at: http://www.epsg-registry.org/
Use the Query by Filter option and enter: North American Datum 1983.
This yields -> EPSG:6269.
Hope this works for you.