I am using postgis for my spatial database.
in my database I have a set of lines in one table and a set of points in another table. How Is it possible to determine which fits best as a point of intersection of two lines? What i am after is something related to the st_intersection function.
PostGIS's ST_INTERSECTION will give you the geometry of the point of intersection between the two lines, and then a MIN(ST_DISTANCE([...], [...]) between this intersection and your points will give you the best fit.
http://www.postgis.org/docs/ST_Intersection.html
http://www.postgis.org/docs/ST_Distance.html
Related
I have a column with gps coordinates, in each row a set of geo-polygon coordinates. Most lines have duplicate gps coordinates (complete coincidence of longitude and latitude in one column).
Example:
MULTIPOLYGON
23.453411011874813 41.74245395132344
23.453972640029299 41.74214208390741
23.453977029220994 41.741827739090233
23.454523642352295 41.741515869012523
23.441100249526403 41.741203996333724
23.441661846243466 41.740892121053918
23.456223434003668 41.74058024317317
23.441661846243466 41.740892121053918
I need to remove duplicate coordinates (bold)
I'm using teradata 16.20.32.17
Thank you!
Have a look at SimplifyPreserveTopology, it's not exactly removing duplicates, but probably close to what you want:
Simplifies a geometry by removing points that would fall within a
specified distance tolerance.
The simplification always returns a
valid geometry. Simplified geometries require less storage space and
fewer spatial operations during geospatial manipulations. Consequently
operations on simplified geometries generally perform faster. Smaller
tolerance values result in a geometry closer to the input geometry,
but will remove fewer vertices. Larger tolerance values will remove
more vertices, but the resulting simplified geometry will be less
similar to the original input.
I'm looking at the freely available Solar potential dataset on Google BigQuery that may be found here: https://bigquery.cloud.google.com/table/bigquery-public-data:sunroof_solar.solar_potential_by_censustract?pli=1&tab=schema
Each record on the table has the following border definitions:
lat_max - maximum latitude for that region
lat_min - minimum latitude for that region
lng_max - maximum longitude for that region
lng_min - minimum longitude for that region
Now I have a coordinate (lat/lng pair) and I would like to query to see whether or not that coordinate is within the above range. How do I do that with BQ Standard SQL?
I've seen the Geo Functions here: https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions
But I'm still not sure how to write this query.
Thanks!
Assuming the points are just latitude and longitude as numbers, why can't you just do a standard numerical comparison?
Note: The first link doesn't work without a google account, so I can't see the data.
But if you want to become spatial, I'd suggest you're going to need to take the border coordinates that you have and turn them into a polygon using one of: ST_MAKEPOLYGON, ST_GEOGFROMGEOJSON, or ST_GEOGFROMTEXT. Then create a point using the coords you wish to test ST_MAKEPOINT.
Now you have two geographies you can compare them both using ST_INTERSECTION or ST_DISJOINT depending on what outcome you want.
If you want to get fancy and see how far aware from the border you are (which I guess means more efficient?) you can use ST_DISTANCE.
Agree with Jonathan, just checking if each of the lat/lon value is within the bounds is simplest way to achieve it (unless there are any issues around antimeridian, but most likely you can just ignore them).
If you do want to use Geography objects for that, you can construct Geography objects for these rectangles, using
ST_MakePolygon(ST_MakeLine(
[ST_GeogPoint(lon_min, lat_min), ST_GeogPoint(lon_max, lat_min),
ST_GeogPoint(lon_max, lat_max), ST_GeogPoint(lon_min, lat_max),
ST_GeogPoint(lon_min, lat_min)]))
And then check if the point is within particular rectangle using
ST_Intersects(ST_GeogPoint(lon, lat), <polygon-above>)
But it will likely be slower and would not provide any benefit for this particular case.
So I added geometry columns to a spatial table and using some of the msdn references I ended up specifying the SRID as 0 like so:
update dbo.[geopoint] set GeomPoint = geometry::Point([Longitude], [Latitude], 0)
However, I believe this was a mistake, but before having to update the column, is 0 actually the default = 4326? The query works as long as I specify the SRID as 0 on the query, but I'm getting weird results in comparison to the geography field I have... SRID 0 does not exist in sys.spatial_reference_systems and I haven't been able to dig up any information on it. Any help would be appreciated.
A SRID of 0 doesn't technically exist, it just means no SRID -- ie, the default if you forget to set it. So, technically, you can still perform distance, intersection and all other queries, so long as both sets of geometries have a SRID of 0. If you have one field of geometries with a SRID of 0 and another set with a SRID that actually exists, you will most likely get very strange results. I remember scratching my head once when not getting any results from a spatial query in exactly this situation and SQL Server did not complain, just 0 results (for what is is worth Postgis will actually fail, with a warning about non-matching SRIDs).
In my opinion, you should always explicitly set the SRID of your geometries (or geographies, which naturally will always be 4326), as not only does it prevent strange query results, but it means you can convert from one coordinate system to another. Being able to convert on the fly from lat/lon (4326), to Spherical Mercator (3857), as used in Google Maps/Bing, which is in meters, or some local coordinate system, such as 27700, British National Grid, also in meters, can be very useful. SQL Server does not to my knowledge support conversion from one SRID to another, but as spatial types are essentially CLR types, there are .NET libraries available should you ever need to do so, see Transform/ Project a geometry from one SRID to another for an example.
If you do decide to change you geometries, you can do something like:
UPDATE your_table SET newGeom = geometry::STGeomFromWKB(oldGeom.STAsBinary(), SRID);
which will create a new column or to do it in place:
UPDATE geom SET geom.STSrid=4326;
where 4326 is just an example SRID.
There is a good reference for SRIDs at http://spatialreference.org/, though this is essentially the same information as you find in sys.spatial_reference_systems.
SRIDs are a way to take into account that the distances that you're measuring on aren't on a flat, infinite plane but rather an oblong spheroid. They make sense for the geography data type, but not for geometry. So, if you're doing geographic calculations (as your statement of "in comparison to the geography field I have"), create geography points instead of geometry points. In order to do calculations on any geospatial data (like "find the distance from this point to this other point"), the SRID of all the objects involved need to be the same.
TL;DR: Is the point on the Cartesian plane? Use geometry. Is the point on the globe? Use geography.
We have an application that has a database full of polygons (currently stored as points) that a .net app pulls out and checks if they overlap.
I occurred to me that it would be much nicer to convert these point arrays to polygon / polyline objects within the database and use sql to get a bool of weather they overlap or not.
I have seen different methods suggested to do this but non of the examples given were quite in-line with my needs.
I would be very happy to receive input from those kind enough to offer their experience.
Additional:
In response to questions: It is indeed 2D. and yes any crossover of the two is considered true. The polygons have n points and can be concave. The polygons will be saved as 1 per row (after data conversion task) as polygons (i.e. the polygon type .. it might be called something else spatial / geom my memory is not on my side right now)
You can use .STIntersection with .STAsText() to test for overlapping polygons. (I really hate the terminology Microsoft has used (or whoever set the standard terms). "Touching," in my mind, should be a test for whether or not two geometry/geography shapes overlap at all, not just share a border.)
Anyway....
If #RadiusGeom is a geometry representing a radius from a point, the following will return a list of any two polygons where an intersection (a geometry that represents the area where two geometries overlap) is not empty.
SELECT CT.ID AS CTID, CT.[Geom] AS CensusTractGeom
FROM CensusTracts CT
WHERE CT.[Geom].STIntersection(#RadiusGeom).STAsText() <> 'GEOMETRYCOLLECTION EMPTY'
If your geometry field is spatially indexed, this runs pretty quickly. I ran this on 66,000 US CT records in about 3 seconds. There may be a better way, but since no one else had an answer, this was my attempt at an answer for you. Hope it helps!
Calculate and store the bounding rectangle of each polygon in a set of new fields within the row which is associated with that polygon. (I assume you have one; if not, create one.) When your dotnet app has a polygon and is looking for overlapping polygons, it can fetch from the database only those polygons whose bounding rectangles overlap, using a relatively simple SQL SELECT statement. Those polygons should be relatively few, so this will be efficient. Then, your dotnet app can perform the finer polygon overlap calculations in order to determine which ones of those really overlap.
Okay, I got another idea, so I am posting it as a different answer. I think my previous answer with the bounding polygons probably has some merit on its own, even if it was to reduce the number of polygons fetched from the database by a small percentage, but this one is probably better.
MSSQL supports integration with the CLR since version 2005. This means that you can define your own data type in an assembly, register the assembly with MSSQL, and from that moment on MSSQL will be accepting your user-defined data type as a valid type for a column, and it will be invoking your assembly to perform operations with your user-defined data type.
An example article for this technique on the CodeProject: Creating User-Defined Data Types in SQL Server 2005
I have never used this mechanism, so I do not know details about it, but I presume that you should be able to either define a new operation on your data type, or perhaps overload some existing operation like "less-than", so that you can check if one polygon intersects another. This is likely to speed things up a lot.
I have a table where each row is part of a New Zealand map. What I really want to know is is a point within the map (ie the country data) or is it in the water.
I understand how StIntersects works but all examples are for a single Polygon or LineString but I have a table of LineStrings - 130 rows that define the country border.
Lots of rows like this
LINESTRING (6252032.7308424888 -3161950.9615992079, 6252033.7275789445 -3161929.3581238855, 6252011.5227283547 -3161906.1086780191, 6251992.0438580718 -3161880.6299652755)
So I think I need to sort of put all the line strings together to make my country border a single polygon or something like that, but I do not know how to do that.
Can someone give me an example of how I could do this?
The original data was from a ShapeFile from www.koordinates.com called New Zealand Coastlines. I then used Shape2Sql to import to SQL Server using Planer Geometry.
Geometry (spheric) in Shape2File said "Data projects or extent is outside the bounds of what is supported by the SqlGeography type)
Hope I have provided enough information?
Cheers Chris
You have most likely moved on from this but I am posting for future use.
If I understand you correctly, you need to create one polygon from a table of LINESTRINGs that make up the boundary of the polygon?
First, combine all of the LINESTRINGs in your table into one geometry like this:
DECLARE #g geometry
SELECT TOP 1 #g = geom from #geom_tmp
SELECT
#g = #g.STUnion(geom)
FROM
#geom_tmp
SELECT #g
Then you want to create a polygon from your single-line boundary. There are only two things that differ between your single-line boundary string and a polygon, first we replace "LINESTRING" with "POLYGON". Then we add a set of parentheses since a polygon's WKT string separates multiple polygons with parentheses like this:
DECLARE #str NVARCHAR(max)
SET #str = REPLACE(REPLACE(#g.STAsText(),'(','((') + ')','LINESTRING','POLYGON')
SET #g = GEOMETRY::STGeomFromText(#str,0)
SELECT #g
Which will give you your polygon of the country.
Then you simply see if your point intersects the polygon (#p is the point geometry):
SELECT #p.STIntersects(#g)
-- OUTPUT is 1 if it intersects and 0 if it does not.
OR if your points are in a table, you could select the list of points that intersect the country as shown below if the point table geometry column is called "point".
SELECT *
FROM point_table
WHERE point.STIntersects(#g) = 1
Since there are many of us who cannot move to SQL server 2012 any time soon, this comes in handy. Hope it helps.
The classic approach to determine whether two points are on the same side (inside or outside) of a polygon, is to calculate the number of intersections between a line connecting the two and borders of the polygon. Even number (incl. 0) is same side, odd is different sides.
So define one (any) point which is inside New Zealand for sure (preferably near geometric middle), then a line that connects it with the point you want to check, then calculate the number of lines it intersects. If it's 0 or even, the other point is on the same side (that is in New Zealand.) If it's odd, the point is outside the country borders. You don't need to worry about ordering or connecting the border lines.
It becomes more tricky if the line crosses exactly through a joint point between two border lines, but StIntersects won't save you against that, and besides if you work on real values with 17 significant places, the likehood for this to occur is minimal.
The algorithm is good here in that it works for multiple disjoint polygons (isles) just as well as for single irregular polygon. The only requirement is all the lines are closed.
Of course to get that to work you'd have to transform linestrings into a set of single lines and store these, because you need to find number of intersections, not just fact: line intersects polygon (n times) vs 0 times.
Let me see if I understand your problem.
You wish to determine if a pre-determined point is either INSIDE NZ or OUTSIDE. Now, you have the coastline of NZ, right? This coastline is around 130 rows ... but we need to make this one single row .. and THEN see if the point lies inside this boundary or outside.
If this is correct, then the first thing you'll need to do is to join all the linestrings into a single massive polygon .. and we need this final single row as a Sql Server 2008 GEOGRAPHY type.
So - first some help. Jump over to Codeplex and grab this library - sql spatial tools. In this library, there is a method to JOIN all the linestrings. I think it's called GeographyUnionAggregate . Figure out how to run this stored proc which will join all the linestrings together (assuming none of them are messed up).
Once this task is done, you will have a single GEOGRAPHY row which repesents the entire coastline of NZ.
Now, it's a simple sql statement to see if the point exists/intersects the boundary (the country of NZ) or not :-
DECLARE #SomePoint GEOGRAPHY
SET #SomePoint = geography::STGeomFromText('POINT(-122.358 47.653)', 4326);
SELECT CountryId, Name
FROM Countries a
INNER JOIN a.AdministrativeBoundary.STIntersects(#SomePoint) = 1
And that should return you one result :)