Find geometries with coordinates that do not belong in projection - postgis

I was recently supplied data in a shape file projection EPSG:4326. I imported this into my PostGIS database and then tried to transform to 3857. I got the error
ERROR: transform: couldn't project point (-99762.4 -2.87277e+006 0): latitude or longitude exceeded limits (-14)
Even after applying st_force2d and st_makevalid I still couldn't transform until I managed to track down a delete the one geometry that was "out of bounds" for Lat/Lng.
My question is: how do I easily find geometries that don't fit in the current projections envelope?

In case of 4326 this should work:
SELECT * FROM your_table WHERE
(st_x(geom) NOT BETWEEN -180 AND 180)
OR
(st_y(geom) NOT BETWEEN -90 AND 90) ;

(I would have left this as a comment, but since I can't, here it is.)
This answer could be helpful:
Get projection limits from Postgis
Basically:
PostGIS doesn't know about a projection's bounds and you would need to make a new table to collect it.
Even if the value is contained in a projection's limits, it doesn't mean that it is right for this projection. This method can only ensure that the transform process will proceed and get you a result, it can not ensure that the data is correct.

For a more generic solution, you could use a custom transform function which catch the error:
CREATE OR REPLACE FUNCTION transform_safe(geom geometry, srid int) RETURNS geometry AS $$
BEGIN
IF ST_Srid(geom) = 0 THEN
RAISE Exception 'Input geometry has unknown (0) SRID';
END IF;
BEGIN
RETURN ST_Transform(geom, srid);
EXCEPTION WHEN internal_error THEN
RAISE WARNING '%: %',SQLSTATE,SQLERRM;
END;
RETURN NULL;
END;
$$
language plpgsql;
This behaves the same as ST_Transform but returns NULL if the coordinates are out of bounds.
In example, so could you identify the records with invalid coordinates:
SELECT id FROM polygon_table WHERE transform_safe(geom) IS NULL AND geom IS NOT NULL;

Related

Delphi, code example code getting list of overlapping polygons with SQL Server Spatial

The overlap between polygons can be evaluated using SQL Server spatial .STContains function (https://learn.microsoft.com/en-us/sql/t-sql/spatial-geometry/stcontains-geometry-data-type?view=sql-server-ver16&viewFallbackFrom=sql-server-ver18)
Can I get some code sample to get the list of polygons located inside a given polygon (the record index should be the query parameter), return a list of records inside this polygon?
select *
from table
where PolygonsInside (RecordIndex = 1)
How to get to this SQL query?
Your description ("overlap between polygons") doesn't necessarily match the function you've chosen (from the same documentation you've linked to, STContains() "Returns 1 if a geometry instance completely contains another geometry instance.".); STIntersects() may be a better choice.
Regardless of any of that, here's a query you'd write to find any polygon from a table that overlaps given the ID of another polygon in the same table.
select overlaps.ID, overlaps.Polygon
from PolygonTable as given
join PolygonTable as other
on other.Polygon.STIntersects(given.Polygon) = 1
and other.ID <> given.ID
where given.ID = 1;
That is, if you provide an ID of 1, that query will find any polygon in the table that intersects with that. Note, I've added a predicate in the join so as not to also return the polygon that has the ID provided - that may or may not be what you want but it's easily removed if you do want to return that one.

Spatial Join in SQL Server

I come from a mining and exploration background. I have a list of points (with ID and X and Y coordinates).
Example
I have another table which contains polygons (claim numbers).
I am trying to find out which points fall within which polygons. My coordinates are in UTM Projection.
Thank you in advance!
I was trying the following code however my query is not returning results.
SELECT
pg.claim_number,
p.DHId
FROM leasehold as pg
JOIN
(SELECT
DHId,
X,
Y,
geometry::STPointFromText('POINT(',X,' ',Y,'), 0) AS [geom]
FROM collar
WHERE X is not null AND
Y is not null AND
claim_number is null) AS p
ON pg.Shape.STIntersects(p.geom) = 1
I was expecting to get a list with claim_number from polygon table which each DHId from point table intersects or falls within.
It looks like there just a syntax/quoting issue. I cleaned it up a bit and replaced STPointFromText with Point which is an MS-specific extension but doesn't require you to create WKT just to get a point. But that's really all I changed - I'd expect your general approach to work.
SELECT
pg.claim_number,
p.DHId
FROM leasehold as pg
JOIN (
SELECT
DHId,
X,
Y,
geometry::Point(X, Y, 0) AS [geom]
FROM collar
WHERE X is not null AND
Y is not null AND
claim_number is null
) AS p
ON pg.Shape.STIntersects(p.geom) = 1;
That said, I would expect this to not be super performant. You're creating the points on the fly and so will be incurring that cost at run time. As such, there's no way to put a spatial index on that data. If you can, I'd suggest adding a column to your collar table that is the geometry point and, as I implied, put a spatial index on it. Also, if there's not an index on the leasehold.Shape column, I'd put one there as well.

How to make polygon from buffered point collection in postgis

I'm trying to make polygon of an airport which must be given distance from start point and end point of runway given as latitude and longitude.
Query I've made looks like this:
INSERT INTO airport (name, polygon)
VALUES(
'some airport name',
ST_SetSRID(
ST_Collect(
ST_Buffer(ST_MakePoint(160.04518, -9.43196), 100),
ST_Buffer(ST_MakePoint(160.06376, -9.42452), 100)
), 4326
)
);
unfortunately result polygon is very weird, it covers almost all earth. I've also tried to add srid to each point but it also didn't work. Any ideas?
Thanks to https://stackoverflow.com/a/13872887/4270929
before adding buffer to point it must be cast to geography (in geometry is in different unit I guess?)
ST_Buffer(ST_MakePoint(160.04518, -9.43196)::geography, 100)::geometry,
ST_Buffer(ST_MakePoint(160.06376, -9.42452)::geography, 100)::geometry

How to speed up query that use postgis extension?

I have the following query that checks whether is point (T.latitude, T.longitude) is inside a POLYGON
query = """
SELECT id
FROM T
WHERE ST_Intersects(ST_Point(T.latitude, T.longitude), 'POLYGON(({points}))')
"""
But it works slow, how can I speed up it if I have the following index:
(latitude, longitude)?
The query is slow because it must compute the formula for every possible pair of points. So it makes the postgress server do a lot of math, and it forces it to scan through your whole location table. How can we optimize this? Maybe we can eliminate the points that are too far north or too far south or too far east or west?
1) Add a geometry column of type Geometry(Point) and fill it:
ALTER TABLE T add COLUMN geom geometry(Point);
UPDATE T SET geom = ST_Point(T.latitude, T.longitude);
2) Create a spatial index:
CREATE INDEX t_gix ON t USING GIST (geom);
3) Use ST_DWithin instead of ST_Intersect:
WHERE ST_DWithin('POLYGON(({points}))', geom, 0)
You want actually find the points which are within a polygon, so ST_DWithin() is what you need. From the documentation:
This function call will automatically include a bounding box
comparison that will make use of any indexes that are available
PS:
If you for some reason cannot make the points 1 and 2, so at least use ST_Dwithin instead of ST_Intersect:
WHERE ST_DWithin('POLYGON(({points}))', ST_Point(T.latitude, T.longitude), 0)
The last parameter is the tolerance.
You can easly speed up your spatial queries that adding t1.geom&&t2.geom condition to your scripts
This condition;
required spatial indexies so your spatial columns must have spatial indexies
returns approximate result (but with st_ Operators gives exact result)
Here is a example at my database and query timings;
select p.id,k.id, p.poly&&k.poly as intersects
from parcel p , enterance k
where st_contains(p.poly,k.poly) and p.poly&&k.poly
--without && 10.4 sec
--with && 1.6 sec
select count(*) from parcel --34797
select count(*) from enterance --70715
https://postgis.net/docs/overlaps_geometry_box2df.html

Spatial Indexing

I want to create a large database of GPS coordinates that can be queried by saying "Return all coordinates that are within 'n' metres of [this coordinate]".
I would like to know how to implement Quadtree Indexing in Sqlserver2008?
I want to write a .net module that calls the query which uses quad tree so that i can retrieve the objects so quickly.
How can i implement the above functionality?
Thanks in advance
CREATE TABLE mytable (id INT NOT NULL, mypoint GEOGRAPHY NOT NULL, ...)
CREATE SPATIAL INDEX SX_mytable_mypoint ON mytable (mypoint)
SELECT *
FROM mytable
WHERE mypoint.STDistance(geography::STGeomFromText(N'POINT (latitude longitude)', 4326) <= #N
I know that your article specifically references implementing the QuadTree in SqlServer2008, but as an option you could use one implemented in managed code.
Seem my article:
http://www.codeproject.com/KB/recipes/QuadTree.aspx

Resources