Find points inside the intersection of polygons in PostgreSQL/PostGIS - postgresql

I want to find the points inside the intersection (Figure 1) of polygons in PostgreSQL.
Figure 1 example
I use psycopg2 and the code that I used is:
intersects = """select ST_Intersects( ST_GeographyFromText('SRID=4326; POLYGON(( 32.0361328 33.6877818, 31.9042969 33.5780147,33.5742188 11.3507967,66.2695313 20.4270128, 51.9433594 34.270836, 32.0361328 33.6877818))'),
ST_GeographyFromText('SRID=4326; POLYGON((33.7060547 37.1953306,36.6943359 16.0880422,64.9072266 12.4258478,64.8632813 37.0551771,33.5742188 37.1953306,33.7060547 37.1953306))')), col.vessel_hash,ST_X(col.the_geom) AS long, ST_Y(col.the_geom) AS lat
from samplecol as col"""
cursor.execute(intersects)
pointsINtw = cursor.fetchall()
count = 0;
shipsrecords = open("/home/antonis/Desktop/testme1.txt", "w")
for ex in pointsINtw:
if str(ex[0])=='True':
count = count + 1
shipsrecords.write(str(ex) + "\n")
print (CBLUE + "Number of returned results: " + CBLUEEND), count
Example record:
vessel_hash | speed | latitude | longitude | course | heading | timestamp | the_geom
--------------+--------+---------+-------+-------------+-------------+--------+---------+--------------------------+----------------------------------------------------
103079215239 | 5 | -5.41844510 | 36.12160900 | 314 | 511 | 2016-06-12T06:31:04.000Z | 0101000020E61000001BF33AE2900F424090AF4EDF7CAC15C0
The problem is that above code does not work properly. I create two polygons like Figure 1 and I know that inside the intersection exist some points. But the code always returns all points from db.
If I create two polygons that do not intersect then the algorithm seems to work properly as it does not return any point.
Does anyone know what am I doing wrong?

demo:db<>fiddle (of your query, with your polygons, own points),
visualisation of the situation (maybe Chrome necessary)
ST_Intersects() only checks if the two given polygons share some space. It is true, they share. But there is no part within your query that includes the check with the points. You only call the intersection check but without any usage of your point column.
I believe you need to calculate the intersection polygon (ST_Intersection()) instead of only check for its existance. After that you can take this result to check whether your points are in it or not (ST_Contains()):
Pseudocode:
SELECT
ST_Contains(
ST_Intersection(my_geometry1, my_geometry2),
my_pointgeometry
)
...
demo:db<>fiddle
(Demo uses geometry instead of geography and the polygon needs to get valid for some reasons; so you need to adapt this to your use case)

Related

How can I merge two Mbtiles?

I have created 2 Mbtiles via QGIS: 1) one Mbtile is from zoom 0 until 10 & is a map of the whole world, 2) and another one from zoom 0 until 17 & is a detailed map of one country.
I would like to merge the two Mbtiles, and have the Mbtile of the detailed country overlapping the Mbtile of whole world. Also the merged result to be from zoom 0 til 17 (the whole world would disappear at zoom 10, but the country will remain until zoom 17).
What program/method should I use? Is it possible to merge them via QGIS?
I use Python to merge MBTiles files. Be sure to update the matadata table noting the min max zoom. They are just sqlite databases with a unique extension.
This example does not include data validation. I did not test this example -- as it is stripped down from where I batch process output from QGIS.
It is less problematic to use an IDE other than QGIS's python interface. Does not require anything specific to QGIS or PyQGIS.
import sqlite3 as sqlite
def processOneSource(srcDB, dstDB):
# create_index_sql = "CREATE UNIQUE INDEX tile_index on tiles (zoom_level, tile_column, tile_row);"
# dstDB.connection.execute(create_index_sql)
# the index forces an error if there is already a tile for the same zxy
sqlite_insert_blob_query = """ INSERT INTO tiles (zoom_level, tile_column, tile_row, tile_data) VALUES (?, ?, ?, ?)"""
tiles = srcDB.connection.execute('select zoom_level, tile_column, tile_row, tile_data from tiles;')
for t in tiles:
z = t[0]
x = t[1]
y = t[2]
data = t[3]
# example of how you might include exclude tiles
if not (z == 12 or z == 13 or z == 14 or z == 15 or z == 16):
continue
print(str((t[0], t[1], t[2])))
data_tuple = (t[0], t[1], t[2], t[3])
try:
dstDB.connection.execute(sqlite_insert_blob_query, data_tuple)
except Exception as e:
print(e)
dstDB.commit()
if __name__ == '__main__':
srcDB = sqlite.connect("path_to_yourfilename")
dstDB = sqlite.connect("path_to_yourfilename")
processOneSource(srcDB, dstDB)
You can use tile-join, it has a bunch of flags so you can customize the output.

Postgis - ST_ShortestLine not correct with lat lon

I'm calculating the shortest line between a Line and a Point for very short distances (some meters), using Postgis ST_ShortestLine:
SELECT ST_AsText(
ST_ShortestLine(ST_GeomFromText('POINT(2.33123610021 48.87902639841)', 4326),
ST_GeomFromText('LINESTRING ( 2.33122725689 48.87902421718, 2.33123229444 48.87901190847)', 4326))
) As sline;
I get a result which does not seem coherent, the given line not being the shortest one:
LINESTRING(2.33123610021 48.87902639841,2.331227760998549 48.87902298544515)
Here is a drawing of the result, using the Mercator projection (JOSM).
What could explain this?
If you're relying on your eyes to determine if the drawn line is the shortest one you might have been mislead to this conclusion. ST_ShortestLine will return a line with exact same length of ST_Distance, which is the minimum 2D cartesian distance of two geometries. And it is exactly what is happening:
WITH j (line,point) AS (
VALUES ('SRID=4326;POINT(2.33123610021 48.87902639841)',
'SRID=4326;LINESTRING(2.33122725689 48.87902421718, 2.33123229444 48.87901190847)')
)
SELECT
ST_Length(ST_ShortestLine(point,line)), -- length of the shortest line
ST_Distance(line,point), -- distance between 'point' and 'line'
ST_AsEWKT(ST_ShortestLine(point,line)) -- the shortest line as EWKT
FROM j;
st_length | st_distance | st_asewkt
-----------------------+-----------------------+----------------------------------------------------------------------------------------
9.010592472335791e-06 | 9.010592472335791e-06 | SRID=4326;LINESTRING(2.331227760998549 48.87902298544515,2.33123610021 48.87902639841)
(1 row)
Perhaps you share the result you're expecting and we can go from there.

Get point along a linestring that is two feet away from the first point

I have the following linestring:
SELECT ST_GeomFromText('LINESTRING(-97.83396022 29.98609860,-97.83391790 29.98613790)',4326);
I need to add a point between the linestring, which is 2 feet from the first point
You can use ST_LineInterpolatePoint.
Since it takes a proportion of the line, the first step is to compute it: convert 2ft to meters, divide by the length of the line in meters, that you get by casting it to geography.
WITH src(geom) AS (values (ST_GeomFromText('LINESTRING(-97.83396022 29.98609860,-97.83391790 29.98613790)',4326)))
SELECT ST_AsText(ST_LineInterpolatePoint(geom, 2 * 0.3048/ st_length(geom::geography)))
FROM src;
st_astext
-------------------------------------------
POINT(-97.8339558996568 29.9861026120389)
To create a line from the start that is 2ft long, you can use st_lineSubstring instead
SELECT st_lineSubstring(geom, 0, 2 * 0.3048/ st_length(geom::geography))

conditional statement with logical operators for thingspeak data

I am working on a thingspeak code on matlab analysis for my weather station which checks last 24 readings and then gives alert on the basis of given conditions, and I gave this condition but I guess I am messing up with something hence getting wrong results. I want the answer to be overall logical 1 or 0. I get 1's for even the values that should not give me one and the answer for both variables is a 24*1 logical array. But even then the tweets are not being generated as well. Here's my code;
t =thingSpeakRead(293182,'Fields',1,'NumPoints',24,'OutputFormat','matrix');
h =thingSpeakRead(293182,'Fields',2,'NumPoints',24,'OutputFormat','matrix');
DangerAlert = ((t>42.5)&(t<43.5)&(h>17)&(h<21))|(((t>40.5)&(t<43.5))&((h>21)&(h<27)))|((t>39.5)&(t<43.5)&(h>27)&(h<31)) | ((t>38.5)&(t<43.5)&(h>31)&(h<37))| ((t>37.5)&(t<42.5)&(h>37)&(h<41))| ((t>36.5)&(t<40.5)&(h>41)&(h<47))| ((t>35.5)&(t<39.5)&(h>47)&(h<51))| ((t>34.5)&(t<38.5)&(h>51)&(h<57))| ((t>33.5)&(t<38.5)&(h>57)&(h<68))| ((t>33.5)&(t<37.5)&(h>63)&(h<68)) | ((t>32.5)&(t<38.5)&(h>68)&(h<73)) | ((t>31.5)&(t<35.5)&(h>73)&(h<83))| ((t>30.5)&(t<33.5)&(h>83)&(h<88)) | ((t>29.5)&(t<33.5)&(h>83)&(h<93))| ((t>29.5)&(t<32.5)&(h>93)&(h<100))
HeatStrokeAlert=((t>42.5)&(t<43.5)&(h>37)&(h<41)) | ((t>40.5)&(t<2.5)&(h>41)&(h<47)) | ((t>39.5)&(t<41.5)&(h>47)|(h<51))| ((t>38.5)&(t<40.5)&(h>51)&(h<57))| ((t>38.5)&(t<39.5)&(h>57)&(h<63))| ((t>37.5)&(t<38.5)&(h>63)&(h<68))| ((t>36.5)&(t<38.5)&(h>68)&(h<78))| ((t>35.5)&(t<37.5)&(h>73)&(h<83)) | ((t>34.5)&(t<36.5)&(h>83)&(h<88)) | ((t>33.5)&(t<36.5)&(h>88)&(h<93)) | ((t>33.5)&(t<35.5)&(h>93)&(h<97)) | ((t>32.5)&(t<34.5)&(h>97))
if DangerAlert
webwrite('http://api.thingspeak.com/apps/thingtweet/1/statuses/update','api_key', 'XXXXXXXXXXXXX', 'status', 'Alert!Dangerously High temperature tomorrow!')
end
if HeatStrokeAlert
webwrite('http://api.thingspeak.com/apps/thingtweet/1/statuses/update','api_key', 'XXXXXXXXX', 'status', 'Alert!Heat Stroke alert tomorrow!')
end
I know the blunder is minor.But this needs to solve.
Your range values for t go from 29.5 to 43.5, and for h go from 17 to 100. So any value you put in between those numbers will give you a 1, because you are using the OR statements ||. So if ANY one of those is true, it will come back true (=1).
Also, for the website, make sure you follow these directions:
https://www.mathworks.com/help/matlab/ref/webwrite.html
Make sure you have a ThinkSpeak account, and try changing your URL to match their format:
[thingSpeakURL 'update'];
So add 'update' string and use brackets.
Also, set your if statement expression to one. So:
if DangerAlert = 1

postgis convert Points to polygon

what is the easy way to convert points to polygon?
i've tried this query
SELECT ST_GeomFromText('POLYGON((157 -536.0,157 -537.0,157 -538.0,157 -539.0,157 -540.0,157 -541.0,157 -542.0,157 -543.0,157 -544.0,157 -545.0,158 -545.0,159 -545.0,160 -545.0,161 -545.0,162 -545.0,163 -545.0,164 -545.0,165 -545.0,165 -544.0,165 -543.0,165 -542.0,165 -541.0,165 -540.0,165 -539.0,165 -538.0,165 -537.0,165 -536.0,164 -536.0,163 -536.0,162 -536.0,161 -536.0,160 -536.0,159 -536.0,158 -536.0,157.0 -536.0))');
but its results are not as expected as shown below
which is supposed to be like this
Obviously your points are not in the correct order to define a polygon., and as the commenter pointed out, you have more than one polygons.
You could divide them into sets that make each polygon (manually?), and construct a multipolygon as follows:
SELECT ST_AsText(ST_Collect(ARRAY[ST_GeomFromText('POLYGON(..first polygon...)'),ST_GeomFromText('POLYGON(..2nd polygon...)',...,ST_GeomFromText('POLYGON(..last polygon...)')]));