Search for points from multiple polygons - openstreetmap

I am using ClusterPoint database to access Open Street Map data (https://github.com/clusterpoint/osm), but I'd like to find POI contained within multiple separate polygons.
Is there any example available how to define and use multiple polygons within query?

To use multiple polygons in one query, you need to define them under <shapes> tag. Each polygon should have individual name. If you want to search within multiple polygons, than use OR operator "{}" in query.
Example with two polygons and one circle could look like:
<query>
{><polygon1 ><polygon2 ><circle1}
</query>
<shapes>
<polygon1>lat1 lon1; lat2 lon2; lat3 lon3; lat4 lon4; lat5 lon5; ...
<coord1_tag_name>lat</coord1_tag_name>
<coord2_tag_name>lon</coord2_tag_name>
</polygon1>
<polygon2>lat1 lon1; lat2 lon2; lat3 lon3; lat4 lon4; lat5 lon5; ...
<coord1_tag_name>lat</coord1_tag_name>
<coord2_tag_name>lon</coord2_tag_name>
</polygon2>
<circle1>
<center>lat lon</center>
<radius>10 km</radius> <!-- here you can define distance in "km" or in "mi" -->
<coord1_tag_name>lat</coord1_tag_name>
<coord2_tag_name>lon</coord2_tag_name>
</circle1>
</shapes>
If polygons are overlapped, then matching points within this area will not "duplicate" in result set (will be displayed once).

Related

Buffers (Circle) in PostGIS

I have to extend the normal GeoJSON format to add some unsopported polygon like Circle.
{
"type": "Circle",
"radius" : 0.001,
"coordinates": [
5.417075157165527,
43.29129488122568
]
}
This is an Example. Coordinates marks the center of circle and radius the radius (in meters).
Searching on PostGis Docs and Stackoverflow, to draw a Circle you have to user ST_BUFFER.
So Im using:
ST_Buffer(ST_GeomFromGeoJSON(<center of circle>),0.001, 'quad_segs=16')
Has you know, this draw a Circle only in 0,0 (near Africa). Other locations add a distortion that change the shape in an oval.
Im using 4326.
I have tried to search (even here) but I can't Find a solution to simply draw a circle avoid projection or transforming it.
The only post here is: How to create a circle in meters in postgis?
but its very old and that solution doesn't works.
Isn't it just doing what is supposed to be done? Which is to compensate the distortion due to projecting the ellipsoid into a 2D flat structure? I believe, the further away you get from the equator, the more oval buffers you will see.
Examples:
db=# SELECT ST_AsText(
ST_Buffer(
ST_GeomFromText('SRID=4326;POINT(43.29 5.41)'),0.001, 'quad_segs=16')
);
This query returns a circle at the south-east of Ethiopia:
POLYGON((43.291 5.41,43.2909951847267
5.40990198285967,43.2909807852804 5.40980490967798,43.2909569403357 5.40970971532275,43.2909238795325 5.40961731656764,43.2908819212644 5.40952860326317,43.2908314696123 5.40944442976698,43.2907730104534 5.40936560671584,43.2907071067812 5.40929289321881,43.2906343932842 5.40922698954664,43.290555570233 5.4091685303877,43.2904713967368 5.40911807873565,43.2903826834324 5.40907612046749,43.2902902846773 5.40904305966427,43.290195090322 5.4090192147196,43.2900980171403 5.40900481527333,43.29 5.409,43.2899019828597 5.40900481527333,43.289804909678 5.4090192147196,43.2897097153227 5.40904305966427,43.2896173165676 5.40907612046749,43.2895286032632 5.40911807873565,43.289444429767 5.4091685303877,43.2893656067158 5.40922698954664,43.2892928932188 5.40929289321881,43.2892269895466 5.40936560671584,43.2891685303877 5.40944442976698,43.2891180787356 5.40952860326317,43.2890761204675 5.40961731656764,43.2890430596643 5.40970971532275,43.2890192147196 5.40980490967798,43.2890048152733 5.40990198285967,43.289 5.41,43.2890048152733 5.41009801714033,43.2890192147196 5.41019509032202,43.2890430596643 5.41029028467725,43.2890761204675 5.41038268343237,43.2891180787356 5.41047139673683,43.2891685303877 5.41055557023302,43.2892269895466 5.41063439328416,43.2892928932188 5.41070710678119,43.2893656067158 5.41077301045336,43.289444429767 5.4108314696123,43.2895286032632 5.41088192126435,43.2896173165676 5.41092387953251,43.2897097153227 5.41095694033573,43.289804909678 5.4109807852804,43.2899019828597 5.41099518472667,43.29 5.411,43.2900980171403 5.41099518472667,43.290195090322 5.4109807852804,43.2902902846773 5.41095694033573,43.2903826834324 5.41092387953251,43.2904713967368 5.41088192126435,43.290555570233 5.4108314696123,43.2906343932842 5.41077301045336,43.2907071067812 5.41070710678119,43.2907730104534 5.41063439328416,43.2908314696123 5.41055557023302,43.2908819212644 5.41047139673683,43.2909238795325 5.41038268343237,43.2909569403357 5.41029028467725,43.2909807852804 5.41019509032202,43.2909951847267 5.41009801714033,43.291 5.41))
The same procedure a bit further away from the equator, in Tunisia POINT(9.76 36.61):
POLYGON((9.761 36.61,9.76099518472667 36.6099019828597,9.7609807852804 36.609804909678,9.76095694033573 36.6097097153227,9.76092387953251 36.6096173165676,9.76088192126435 36.6095286032632,9.7608314696123 36.609444429767,9.76077301045336 36.6093656067158,9.76070710678119 36.6092928932188,9.76063439328416 36.6092269895466,9.76055557023302 36.6091685303877,9.76047139673683 36.6091180787356,9.76038268343236 36.6090761204675,9.76029028467725 36.6090430596643,9.76019509032202 36.6090192147196,9.76009801714033 36.6090048152733,9.76 36.609,9.75990198285967 36.6090048152733,9.75980490967798 36.6090192147196,9.75970971532275 36.6090430596643,9.75961731656763 36.6090761204675,9.75952860326317 36.6091180787356,9.75944442976698 36.6091685303877,9.75936560671584 36.6092269895466,9.75929289321881 36.6092928932188,9.75922698954664 36.6093656067158,9.7591685303877 36.609444429767,9.75911807873565 36.6095286032632,9.75907612046749 36.6096173165676,9.75904305966427 36.6097097153227,9.7590192147196 36.609804909678,9.75900481527333 36.6099019828597,9.759 36.61,9.75900481527333 36.6100980171403,9.7590192147196 36.610195090322,9.75904305966427 36.6102902846773,9.75907612046749 36.6103826834324,9.75911807873565 36.6104713967368,9.7591685303877 36.610555570233,9.75922698954664 36.6106343932842,9.75929289321881 36.6107071067812,9.75936560671584 36.6107730104534,9.75944442976698 36.6108314696123,9.75952860326317 36.6108819212644,9.75961731656763 36.6109238795325,9.75970971532275 36.6109569403357,9.75980490967798 36.6109807852804,9.75990198285967 36.6109951847267,9.76 36.611,9.76009801714033 36.6109951847267,9.76019509032202 36.6109807852804,9.76029028467725 36.6109569403357,9.76038268343236 36.6109238795325,9.76047139673683 36.6108819212644,9.76055557023302 36.6108314696123,9.76063439328416 36.6107730104534,9.76070710678119 36.6107071067812,9.76077301045336 36.6106343932842,9.7608314696123 36.610555570233,9.76088192126435 36.6104713967368,9.76092387953251 36.6103826834324,9.76095694033573 36.6102902846773,9.7609807852804 36.610195090322,9.76099518472667 36.6100980171403,9.761 36.61))
And this one much further away, in the north of Norway POINT(23.20 69.94):
POLYGON((23.201 69.94,23.2009951847267 69.9399019828597,23.2009807852804 69.939804909678,23.2009569403357 69.9397097153227,23.2009238795325 69.9396173165676,23.2008819212643 69.9395286032632,23.2008314696123 69.939444429767,23.2007730104534 69.9393656067158,23.2007071067812 69.9392928932188,23.2006343932842 69.9392269895466,23.200555570233 69.9391685303877,23.2004713967368 69.9391180787356,23.2003826834324 69.9390761204675,23.2002902846773 69.9390430596643,23.200195090322 69.9390192147196,23.2000980171403 69.9390048152733,23.2 69.939,23.1999019828597 69.9390048152733,23.199804909678 69.9390192147196,23.1997097153227 69.9390430596643,23.1996173165676 69.9390761204675,23.1995286032632 69.9391180787356,23.199444429767 69.9391685303877,23.1993656067158 69.9392269895466,23.1992928932188 69.9392928932188,23.1992269895466 69.9393656067158,23.1991685303877 69.939444429767,23.1991180787357 69.9395286032632,23.1990761204675 69.9396173165676,23.1990430596643 69.9397097153227,23.1990192147196 69.939804909678,23.1990048152733 69.9399019828597,23.199 69.94,23.1990048152733 69.9400980171403,23.1990192147196 69.940195090322,23.1990430596643 69.9402902846772,23.1990761204675 69.9403826834324,23.1991180787357 69.9404713967368,23.1991685303877 69.940555570233,23.1992269895466 69.9406343932842,23.1992928932188 69.9407071067812,23.1993656067158 69.9407730104534,23.199444429767 69.9408314696123,23.1995286032632 69.9408819212643,23.1996173165676 69.9409238795325,23.1997097153227 69.9409569403357,23.199804909678 69.9409807852804,23.1999019828597 69.9409951847267,23.2 69.941,23.2000980171403 69.9409951847267,23.200195090322 69.9409807852804,23.2002902846773 69.9409569403357,23.2003826834324 69.9409238795325,23.2004713967368 69.9408819212643,23.200555570233 69.9408314696123,23.2006343932842 69.9407730104534,23.2007071067812 69.9407071067812,23.2007730104534 69.9406343932842,23.2008314696123 69.940555570233,23.2008819212643 69.9404713967368,23.2009238795325 69.9403826834324,23.2009569403357 69.9402902846772,23.2009807852804 69.940195090322,23.2009951847267 69.9400980171403,23.201 69.94))
To make your buffer ignore the distortion caused by the projection, consider the following query (POINT in Italy):
SELECT
ST_Buffer(
ST_GeomFromGeoJSON('{"type":"Point","coordinates":[11.26,44.42]}')::geography,
1000,'quad_segs=16')::geometry;
Explanation:
Calculations using GEOMETRY and GEOGRAPHY are made differently, and so are their results. GEOGRAPHY calculates the coordinates over an spherical surface (which can be much slower than GEOMETRY) and uses meters as unit of measurement, while GEOMETRY uses a planar projection and uses the SRS unit.
Note: The GEOMETRY casting in the end of the last query is necessary for the OP's use case, see comments bellow.
May be you can try this it is for a zone one kilometer in diameter like. I test it and it works for me:
SELECT ST_Buffer(
ST_MakePoint(-122.325959,47.625138)::geography,
1000)::geometry;
See here for better understanding.
I didn't test it but hope it will help you.
To recap a bit what Abdullah Alger did in the solution that you can see in the link above:
First he has a database called stores with latitude and longitude column no geometry column with Starbuck dataset.
Then he adds geometry with the query:
SELECT AddGeometryColumn('stores', 'geom', 4326, 'POINT', 2);
After that update the geom column

Mapbox heatmap by point value

There is an example of the heatmap https://www.mapbox.com/mapbox-gl-js/example/heatmap/ by the number of markers/points on the area. But is there a way to display a heatmap by average pins/markers values? For example if I have 5 pins and their average prop value speed=3 then it will be shown as green cluster/heatmap and if their av. prop val is 6 then it will be red cluster/heatmap.
I found that "clusterAggregates" property can help, but can't find any example of using it.
Thanks
I'll leave my way to do so. Old question, which is sometimes risen, but there are no nice sollution, so... Turf's hexgrid (http://turfjs.org/docs/#hexGrid) can help:
const hexagons = hexGrid(bbox, size);
const collection = // collection of your points;
const hexagonsWithin = collect(hexagons, collection, "propertyToAgretateFrom", "propertyToAggregateIn");
const notEmptyHexagonValues = hexagonsWithin.features.filter(({ properties }) => properties.propertyToAggregateIn.length !== 0);
const notEmptyHexagons = {
"type": "FeatureCollection",
"features": notEmptyHexagonValues,
};
// at this point you're having not empty hexagons as a geojson, which you can add to the map
collect is another method from turf, whatcollection should be you can look up in the docs, because it's changing a lot.
The general idea behind is to "divide" visible part of map (bbox) into hexagons by hexGrid method and and aggregate some properties that you need from every marker inside of every hexagon you'll have into the array, so you can get an average value, for example. And assign a color based on it.
Let's say we have feature.properties.propertyToAgretateFrom as 4 and 5 in two markers. After the aggregation, if these markers were inside one polygon, you'll have it feature.properties.propertyToAggregateIn: [4, 5] - this feature is polygon. From this on you can do pretty much everything you want.

search for points within a polygon, postgis

I'm trying to find a coordinate in a polygon coordinate, but can not get it to work. How should I?
Points coordinate in table "location" column "latlon":
A: 60.2653608 -3.6923519
B: 60.241668 -3.652401
SELECT latlon, st_contains(latlon, ST_GeomFromText('MULTIPOLYGON(((60.237949 -3.654019,
60.240247 -3.661016,
60.243500 -3.658463,
60.240127 -3.642761,
60.240127 -3.642761)))', 4326)) FROM location
The documentation says:
boolean ST_Contains(geometry geomA, geometry geomB);
St_Contains Returns TRUE if geometry B is completely inside geometry A
Also, you must reverse the order of the arguments: FIRST the polygon, THEN the point

How to display polygons that are within a specific range (circle) using Leaflet

I am trying find a solution on how to display polygons that are only within a specific range, a circle with radius using leaflet.
Polygons screenshots
Before, I have ask for help regarding on the display of points within a specific range but this time, since a polygon have many nodes/coordinates, i don't have any idea of how it can be done for polygons; a foreach statement?
Any solution? Thanks for the help!
Similar problem solved for displaying points within a specific range
Since you're using MongoDB, the best solution here is (if that's possible), to handle this in the database. Put 2dsphere indexes on your document's loc field and use a $geoWithin query in combination with $centerSphere:
The following example queries grid coordinates and returns all documents within a 10 mile radius of longitude 88 W and latitude 30 N. The query converts the distance to radians by dividing by the approximate radius of the earth, 3959 miles:
db.places.find( {
loc: { $geoWithin: { $centerSphere: [ [ -88, 30 ], 10/3959 ] } }
} )
2dsphere reference: http://docs.mongodb.org/manual/core/2dsphere/
$geoWithin reference: http://docs.mongodb.org/manual/reference/operator/query/geoWithin/
$centerSphere reference: http://docs.mongodb.org/manual/reference/operator/query/centerSphere/
If you really want to do this clientside (which i absolutely wouldn't recommend) and you don't want to build your on solution (which is possible) you could take a look at GeoScript.
GeoScript's geom.Geometry() class has a contains method:
Tests if this geometry contains the other geometry (without boundaries touching).
Geom.geometry reference: http://geoscript.org/js/api/geom/geometry.html
EDIT: Here's the pure JS/Leaflet solution as requested in the comments, this is quick-n-dirty, but it should work. Here the containsPolygon method returns true when all of the polygon's points are within the circle:
L.Circle.include({
'containsPoint': function (latLng) {
return this.getLatLng().distanceTo(latLng) < this.getRadius();
},
'containsPolygon': function (polygon) {
var results = [];
polygon.getLatLngs().forEach(function (latLng) {
results.push(this.containsPoint(latLng));
}, this);
return (results.indexOf(false) === -1);
}
});
Here's a working example: http://plnkr.co/edit/JlFToy?p=preview
If you want to return true if one or more of the polygon's points are within the circle than you must change the return statement to this:
return (results.indexOf(true) !== -1);

Intersecting Layers Returns Empty Collection Despite Visible Intersection

When I perform an intersection of a polygon I draw in OpenLayers and a postgis database layer, it seems that I am getting incorrect results.
Intersection works correctly on some layers. For instance, if I intersect a triangle with a layer of polygons that represent crop fields, I get the following:
The query my app generates to produce the above result is:
SELECT ST_AsText(ST_Intersection(%(geometries_0)s::geometry, %(geometry)s::geometry))
where geometries_0 is my triangle:
POLYGON((-104.84928345939991 40.518951354186285,-104.82319093011056 40.51953858115158,-104.83700967095314 40.50707521626648,-104.84928345939991 40.518951354186285))
and geometry is my layer of crop fields, as well-known text:
MULTIPOLYGON(((-104.841309611298 40.5075331998226,-104.84173356681 40.5069932245841,-104.842041204329 40.50640946683,-104.842224948796 40.5057962996657,-104.842280275816 40.5051688207073,-104.842205823049 40.5045424803865,-104.842003423773 40.5039327015263,-104.841678061729 40.5033544995574,-104.841237748411 40.502822112724,-104.840693325791 40.5023486513933,-104.840058199365 40.5019457751149,-104.839348008051 40.5016234053897,-104.838580239118 40.5013894812384,-104.837773797582 40.5012497635973,-104.836948540713 40.501207693373,-104.836124789073 40.5012643066572,-104.83532282616 40.5014182091969,-104.834562398965 40.5016656107496,-104.833862231727 40.5020004184754,-104.833239564888 40.5024143870601,-104.832709730574 40.5028973218633,-104.83228577506 40.5034373300773,-104.831978137541 40.5040211136997,-104.831794393074 40.5046342970926,-104.831739066055 40.5052617810515,-104.831813518821 40.5058881146554,-104.832015918097 40.5064978757385,-104.832341280141 40.5070760506105,-104.83278159346 40.5076084036796,-104.833326016079 40.5080818278834,-104.833961142505 40.5084846673069,-104.834671333819 40.5088070040565,-104.835439102753 40.5090409023397,-104.836245544289 40.5091806037522,-104.837070801158 40.5092226689759,-104.837894552799 40.5091660624086,-104.83869651571 40.509012177646,-104.839456942906 40.5087648031902,-104.840157110143 40.5084300292289,-104.840779776982 40.5080160977709,-104.841309611298 40.5075331998226)))
However, if I perform the same query with a different layer ("soils"), I get an empty result:
The query is the same:
SELECT ST_AsText(ST_Intersection(%(geometries_0)s::geometry, %(geometry)s::geometry))
with a polygon geometries_0 that should overlap:
POLYGON((-104.84627938530097 40.54511058649626,-104.83460641167578 40.545175808723876,-104.84070039055733 40.537283458057615,-104.84627938530097 40.54511058649626))
and a geometry layer representing soils, similar to the crop fields in the above query:
MULTIPOLYGON(((-104.939716 40.258166,-104.939775 40.258174,-104.939963 40.258159,-104.940159 40.258065,-104.940039 40.257671,-104.939917 40.25749,-104.939928 40.257419,-104.94003 40.257404,-104.940265 40.257641,-104.940632 40.257902,-104.940826 40.258061,-104.941051 40.258188,-104.941123 40.258235,-104.941205 40.258283,-104.941246 40.258275,-104.941287 40.258212,-104.941186 40.258094,-104.941186 40.258007,-104.941167 40.257921,-104.941105 40.257858,-104.941044 40.257786,-104.941045 40.257716,-104.941127 40.257676,-104.94122 40.257653,-104.94141 40.257731,-104.941559 40.257671,-104.941255 40.257181,-104.940857 40.256794,-104.940644 40.256478,-104.940319 40.255997,-104.940003 40.255728,-104.939676 40.255561,-104.939419 40.255544,-104.938895 40.255529,-104.938287 40.255512,-104.938046 40.255528,-104.937733 40.255549,-104.937322 40.255533,-104.937012 40.255577,-104.936947 40.255593,-104.936623 40.255774,-104.936581 40.255924,-104.93658 40.256042,-104.936661 40.256223,-104.93671 40.256436,-104.936842 40.256618,-104.937262 40.256753,-104.937662 40.256818,-104.937897 40.257,-104.938181 40.25745,-104.938374 40.257742,-104.938465 40.257931,-104.938782 40.258051,-104.939121 40.258092,-104.939439 40.258133,-104.939716 40.258166)))
I use the postgis ST_AsText function to convert database layers to well-known text, and I checked to make sure that all layers have the EPSG:4326 projection (using the Find_SRID function).
Why would one layer (crop fields) intersect correctly, and another (soils) not? I've tried the same query using geographies instead of geometries, with the same result.
It returns an empty collection because they don't intersect. In fact, they are 32 km away from each other.
SELECT ST_Intersects(A, B), ST_Distance(A, B)/1000 AS dist_km
FROM (
SELECT
'POLYGON((-104.84627938530097 40.54511058649626,-104.83460641167578 40.545175808723876,-104.84070039055733 40.537283458057615,-104.84627938530097 40.54511058649626))'::geography AS A,
'MULTIPOLYGON(((-104.939716 40.258166,-104.939775 40.258174,-104.939963 40.258159,-104.940159 40.258065,-104.940039 40.257671,-104.939917 40.25749,-104.939928 40.257419,-104.94003 40.257404,-104.940265 40.257641,-104.940632 40.257902,-104.940826 40.258061,-104.941051 40.258188,-104.941123 40.258235,-104.941205 40.258283,-104.941246 40.258275,-104.941287 40.258212,-104.941186 40.258094,-104.941186 40.258007,-104.941167 40.257921,-104.941105 40.257858,-104.941044 40.257786,-104.941045 40.257716,-104.941127 40.257676,-104.94122 40.257653,-104.94141 40.257731,-104.941559 40.257671,-104.941255 40.257181,-104.940857 40.256794,-104.940644 40.256478,-104.940319 40.255997,-104.940003 40.255728,-104.939676 40.255561,-104.939419 40.255544,-104.938895 40.255529,-104.938287 40.255512,-104.938046 40.255528,-104.937733 40.255549,-104.937322 40.255533,-104.937012 40.255577,-104.936947 40.255593,-104.936623 40.255774,-104.936581 40.255924,-104.93658 40.256042,-104.936661 40.256223,-104.93671 40.256436,-104.936842 40.256618,-104.937262 40.256753,-104.937662 40.256818,-104.937897 40.257,-104.938181 40.25745,-104.938374 40.257742,-104.938465 40.257931,-104.938782 40.258051,-104.939121 40.258092,-104.939439 40.258133,-104.939716 40.258166)))'::geography AS B
) AS data;
st_intersects | dist_km
---------------+------------------
f | 32.1052124928391
Something with your map is incorrect.
After some debugging (in addition to some helpful troubleshooting steps) I realized that I was building my WKT blobs incorrectly using the ST_AsText function, specifically for my soils layer. As a result, my intersection was not being applied to the entire set of geometries contained within my soils layer.
Currently my soils layer contains a subset of SSURGO soil map units, some of which do not actually contain a geometry. In order to correctly build a text string representing all non-null geometries, I needed to explicitly join the geometries before converting the result to WKT:
SELECT ST_AsText(ST_Union(the_geom)) FROM schema.layer
did the trick.