geojson postgis ST_DWithin ST_AsGeoJSON - postgis

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.

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.

How to query points north of a certain latitude

I have a Django model with a geodjango PointField:
geopoint = gis_models.PointField(srid=4326, verbose_name='location', geography=True, null=True)
I want to query the model for all points North of a certain latitude.
It ought to be easy, just a > on the latitude component of the point, but I can't find any example of how to do that among the endless examples of distance queries, bounding boxes etc.
Thanks to helpful people of #postgis IRC I have found a way to do this...
Firstly: the way to query against the latitude of a point in PostGIS is via the ST_y function.
As far as I can tell none of the GeoDjango queryset lookups map directly to that function though :(
There is a strictly_above lookup (AFAICT 'above' means 'north of') but it doesn't work for me because my field has geography=True and:
ValueError: PostGIS geography does not support the "strictly_above" lookup.
Thanks to help on #postgis IRC I learned I can cast my geographic field to geometry and thus use ST_y. As a raw PostGIS SQL query it looks like:
SELECT COUNT(id) FROM place WHERE st_y(geopoint::geometry) > 51.508129
The answer:
In Django ORM it looks like:
Place.objects.extra(where=["st_y(geopoint::geometry) > %s"], params=['51.508129']).count()
 Further thoughts:
It's a shame we can't use the existing strictly_above ORM lookup, because of two limitations:
No way in the ORM to cast geography to geometry (though there is an 'accepted' ticket for adding this to geodjango)
If we use extra(select={... to add a cast-to-geometry version of the point field to the queryset we can't filter on it (and "won't fix" in Django), except by adding another extra(where=... clause, in which case we're no better off than above
Out of curiosity I wanted to try the strictly_above query anyway. In PostGIS this is the |>> operator and the raw SQL, comparing my point field to another arbitrary point, looks like:
SELECT COUNT(id) FROM place WHERE geopoint::geometry |>> ST_GeomFromText('Point(-0.128005 51.508129)', 4326);
It returns the same answer as the other query so I'm pretty sure the meaning is the same.

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