How to shrink polygon using postgis? - postgis

I am using postgis 2.2, how can i shrink my polygon to 10 meters using postgis queries ?
This is my polygon
POLYGON((72.89994120597838 19.070245311788284,72.89981782436371
19.069915760688904,72.9002845287323 19.070001951039718,72.9003381729126 19.070341641985888,72.89991974830626 19.07023517176424,72.89994120597838 19.070245311788284))

You can st_buffer function like this
select st_buffer(st_geogfromtext('POLYGON((72.89994120597838 19.070245311788284,72.89981782436371 19.069915760688904,
72.9002845287323 19.070001951039718,72.9003381729126 19.070341641985888,72.89991974830626 19.07023517176424,
72.89994120597838 19.070245311788284))'), -10)
http://www.postgis.org/docs/ST_Buffer.html

Related

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

Find geometries with coordinates that do not belong in projection

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;

Finding polygons within a certain radius of a number of other polygons

I have a table with a bunch of polygons (or multipolygons, I'm not sure...does it matter?) of one type (A) defined in a CTE, and then another of another type (B) in another CTE. I want to filter for just type A polygons that are within a given radius of any of the polygons of type B. How do I do this?
Create a collection of your 'B' polygons using ST_Collect & then use a WHERE clause with ST_DWithin to specify your distance parameter.
For example:
WITH polys_a AS (
SELECT geom
FROM buildings_dc
),
polys_b AS (
SELECT geom
FROM buildings_va
)
SELECT polys_a.*
FROM polys_a,
(
SELECT ST_Collect(geom) as geoms
FROM polys_b
) as c
WHERE ST_DWithin(a.geom, c.geoms, .001);
Note that both sets of geometries may be of different types (e.g. Polygon, Point, MultiPolygon, etc.), but they must be of the same projection/ coordinate system. If you are using standard WGS84 (SRID 4326), the distance parameter is in terms of degrees.

geojson postgis ST_DWithin ST_AsGeoJSON

Can anyone help me how to convert to geojson the result of the query from ST_DWithin (objects within a certain radius)? im lost how to use ST_AsGeoJSON.
Use an aggregate function like ST_Collect to group the geometries:
SELECT ST_AsGeoJSON(ST_Collect(geocolumn))
FROM geotable
WHERE ST_DWithin(geocolumn, 'POINT(1000 1000)', 100.0);
The result will either be a MULTI- geometry, or GEOMETRYCOLLECTION.

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