Get metric distance between two points via a PostgreSQL/PostGIS request - postgresql

I have a question about the use of postgreSQL/postGIS.
I would like to display markers on a map (stored in a database) which are some distance away from the user (coordinates given to the request).
The type of the field of the markers is POINT (I store lat/long).
The user position is detetermined by the Google Map API.
Here is the actual request :
SELECT * FROM geo_points WHERE ST_distance(ST_SetSRID(geo_points.coords::geometry,4326),ST_GeomFromEWKT('SRID=4326;POINT(45.0653944 4.859764599999996)')) > 65
I know (after some research on internet) that the function ST_distance gives me the distance in degree between markers and the user position and that I test the distance in km.
I think I have to use the function ST_tranform to transform the points in metric coordinates.
So my questions are :
- what is the SRID for France
- how can I make this dynamically for the entire world according to the user position ?
I also kow that the function ST_within exists and that could do this. But I anticipate the fact that later, I could need the distance.
Any help would be greatly appreciated
ps: there are maybe solutions in other post, but all the answers I have found during my researches were not really meeting my needs.

Firstly, pay attention to the axis order of coordinates used by PostGIS, it should be long/lat. Currently you are searching in Somalia. Swapping to the coordinates, you would be searching in France.
You can use a geodesic calculation with the geography type, or use geodesic functions like ST_Distance_Spheroid. With the geography type, you may want to use ST_DWithin for higher performance.
Here are geo_points 65 m away or less from the point of interest in France (not Somalia):
SELECT * FROM geo_points
WHERE ST_Distance_Spheroid(
ST_Transform(geo_points.coords::geometry, 4326),
ST_SetSRID(ST_MakePoint(4.859764599999996, 45.0653944), 4326),
'SPHEROID["WGS 84",6378137,298.257223563]') < 65.0;
However, it will be very slow, since it needs to find the distance to every geo_points, so only do this if you don't care about performance and have less than a few thousand points.
If you change and transform geo_points.coords to store lon/lat (WGS84) as a geography type:
SELECT * FROM geo_points
WHERE ST_DWithin(
geo_points::geography,
ST_SetSRID(ST_MakePoint(4.859764599999996, 45.0653944), 4326)::geography,
65.0);

Related

Geopoints: From Single Coordinate to Bounds on map

I try to figure out how to come from a single given coordinate (lat/lon) to the nearest bounds which enclose this coordinate on a map e.g. streets or sea.
Here two examples to give you a better understanding of what I mean:
What i tried already or thought about:
Setting up a Nominatim server and search for the given coordinate via the reverse-function to get the bbox and/or the geojson polygon of this coordinate. -> this only works when the given coordinate is within a POI or for example directly on a street.
Writing an algorithm to walk in all 4 or 8 directions (n/e/s/w) and 'stop' when the map layer/surface changes (change = stop for this direction and mark a bounding-point)
Building up an image-recognition system using TensorFlow to detect the different colors and 'draw' the polygon. Worked with TensorFlow a couple of times but this seems to be the most tricky solution to implement (but at my current understanding the most precise one)
Does someone of you have any other ideas to get a solution for this problem? Would appreciate any kind of approaches
Cheers!
If I got your question right, you might wanna first select all polygons in which the given point is inside of using ST_Contains, and then compute the distance to this point using ST_Distance. If you ORDER BY distance and LIMIT to 1 result you'll get the nearest polygon, e.g.
Data Sample
CREATE TABLE t (gid int, geom geometry);
INSERT INTO t VALUES
(1,'POLYGON((-4.47 54.26,-4.44 54.28,-4.41 54.24,-4.46 54.23,-4.47 54.26))'),
(2,'POLYGON((-4.48 54.25,-4.40 54.25,-4.41 54.23,-4.48 54.23,-4.48 54.25))'),
(3,'POLYGON((-4.53 54.23,-4.44 54.29,-4.38 54.22,-4.53 54.23))');
Query
SELECT gid,ST_AsText(geom) FROM t
WHERE ST_Contains(geom,ST_MakePoint(-4.45, 54.25))
ORDER BY ST_Distance(geom,ST_MakePoint(-4.45, 54.25))
LIMIT 1;
gid | st_astext
-----+------------------------------------------------------------------------
1 | POLYGON((-4.47 54.26,-4.44 54.28,-4.41 54.24,-4.46 54.23,-4.47 54.26))
(1 Zeile)

Setting Unit in POSTGIS

I'm new to PostGIS so my question might sound silly.
Currently working with Points to represent geographical locations (with latitude and longitude only) and was wondering how I can use [ST_DWithin][3] with meters as a unit.
I can't find the right way and been lost in documentation trying to solve this issue.
You need to make sure that your points are geography rather than geometry, as explained in the manual.
So you want a query like:
SELECT s.gid, s.school_name
FROM schools s
LEFT JOIN hospitals h ON ST_DWithin(s.geom::geography, h.geom::geography, 3000)
WHERE h.gid IS NULL;

Lat/Long spatial reference

I am new to PostGIS, am not getting the area of polygon right, my sample data is from Google maps, I know the area of the polygon is 11 acres, but the area returned by st_area doesn't match,
I already referred to a few links like below, but unable to resolve the issue, Internet says google follows 4326 Spatial references, I tried a lot, can you please help, Image attached is the polygon from google maps.
I am expecting an array of such coordinates from the user, I have to calculate the area from PostGIS and give an error back to the user if the area entered is not approximated to calculated area.
https://gis.stackexchange.com/questions/169422/how-does-st-area-in-postgis-work
How do I convert a latitude/longitude pair into a PostGIS geography type?
https://gis.stackexchange.com/questions/56862/what-spatial-reference-system-do-i-store-google-maps-lat-lng-in/56925
17.475197 78.389024
17.4771 78.39044
17.475657 78.391652
17.474408 78.390847
17.475197 78.389024
l_polygon_text='MULTIPOLYGON(((
17.4771000000000001 78.3904399999999981,
17.4751970000000014 78.3890240000000063,
17.4756570000000018 78.3916519999999934,
17.4751970000000014 78.3890240000000063,
17.4744080000000004 78.3908469999999937,
17.4771000000000001 78.3904399999999981)))';
st_area(ST_GeometryFromText(l_polygon_text,4326))
st_area(ST_GeometryFromText(l_polygon_text,2163));
st_area(ST_GeometryFromText(l_polygon_text,2249));
st_area(ST_GeometryFromText(l_polygon_text,3859));
ST_AREA(ST_Transform(ST_GeomFromText(l_polygon_text,4326),31467));
ST_Area(ST_Transform(ST_SetSRID(ST_GeomFromText(l_polygon_text),4326),900913));
polygon
In PostGIS, coordinates must be expressed as longitude first, then latitude. Google uses the opposite.
After swapping the coordinates to the proper order, you can't directly call st_area, else you would get an area in "square degrees" which is meaningless. You would have to project to a suitable local coordinate system, or you can use the geography type which will return an area in m2.
select st_area(st_geogFromText('MULTIPOLYGON(((78.3904399999999981 17.4771000000000001, 78.3890240000000063 17.4751970000000014,78.3916519999999934 17.4756570000000018,78.3890240000000063 17.4751970000000014,78.3908469999999937 17.4744080000000004,78.3904399999999981 17.4771000000000001)))'));
st_area
--------------------
26956.897848576307
That being said, the example you have provided is about 6.5 acres, not 11, because the polygon is not properly defined:

Postgresql postgis ST_DWithin always return true

I need to calculate if one point is not more distant than a given radius from another point. I used the function ST_DWithin, in google maps I get lanLot using "what is here" section of two points. First: (43.2137617, 76.8598076) and second (43.220109 76.865100). The distance between them is 1.25km. My query
SELECT ST_DWithin (
ST_GeomFromText('POINT(76.8598076 43.2137617)',3857),
ST_GeomFromText('POINT(76.865100 43.220109)',3857),
100
);
And it always returns true. I think that I put radius 100 meters and used SRID 3875 to use meters. What is wrong?
The coordinates you are using are not in CRS 3857 but are rather unprojected lat-long, i.e. CRS 4326, so you are looking for points within 100 degrees of each others.
You would need to create the point in 4326, project it in 3857 using ST_Transform and then make the distance computation in meters.
SELECT ST_DWithin (
ST_Transform(ST_GeomFromText('POINT(76.8598076 43.2137617)',4326),3857),
ST_Transform(ST_GeomFromText('POINT(76.865100 43.220109)',4326),3857),
100
);
CRS 3857 is a projection that does not preserve distances that well as you move away from the equator. You may want to use ST_Distance_Sphere instead. Comparing the two methods, the first one gives 1134m between the points and the second one 825m... quite a difference!
SELECT ST_Distance_Sphere (
ST_GeomFromText('POINT(76.8598076 43.2137617)',4326),
ST_GeomFromText('POINT(76.865100 43.220109)',4326))
<= 100;

Calculate distance between two coordinates using postgres?

I´ve got a job offer to work with postgres and I have not much idea of it. The guy told me to build a simple data base which automatically calculates the distance to my house from a list of some other places (bars, pharmacies, museums, whatever...) everything given in geocoordinates.
I have already installed postgres, also postgis and create a data base. May you give me some hints about how I should do this task? Is there any tutorial or resource I could use to make this tasks easier? Should I use postgis?
Thank you.
PostGIS will do this easily. Boundless Geo have an excellent PostGIS tutorial. I also recommend you are familiar with Ch3 & 4 of the PostGIS manual.
I strongly advise you to learn & understand the difference between projected and unprojected coordinates if you're going to be working with spatial data. Projected means the coordinates have been taken from a 'round earth' and adjusted or projected onto to a flat map page (with coordinates normally given in feet or metres depending on the properties of the projection used). This enables computationally efficient normal cartesian calculations to be done for distance, area, direction, intersection, contains etc. There are trade offs for using projections- You can't preserve all of area, distance, shape, direction when you project a curved line or surface onto a flat map. Different projections are optimised for different trade-offs. Calculations on projected data are only accurate over a relatively small portion of the earth's surface. There are many map projections available to suit various needs and localities. If you are going to be working with projected data, you need to pick a projection that suits your purposes and location. If you don't understand projections, your queries can easily produce garbage without realising it.
Unprojected data (ie, raw Lat/Lon coordinates which is what you have) involve much more complicated calculations as they are done on the curved surface of the spheroid representing the earth. There are a number of reference coordinate systems that are used to express Lat/Lon, however the most common is "WGS84" (which is what "GPS" coordinates are expressed in).
PostGIS objects (in the form of "simple features" as defined by the OGC) can be stored as either "geometry" types (projected coordinates) or "geography" types (unprojected Lon/Lat in WGS84: note the order, a common source of confusion!). As a bit of a wrinkle, Lon/Lat (order again!) can also be stored as a "pseudo projected" geometry type (typically with a projection SRID of '4326' for WGS84 Lon/Lat).
The method you use to calculate distance will depend on how you choose to store your points ('geometry' or 'geography').
See ST_Distance from the PostGIS docs for excellent examples of measuring distance using both geometry and geography points. Note, if you wish to calculate projected map distances you will need to pick an appropriate map projection and use ST_Transform to project your points to the appropriate spatial reference system (currently in SRID 4326- "GPS" coordinates). For only a few points the difference won't be at all noticeable, but once you start doing lots of more complex spatial queries, the difference can be significant. PostGIS has a lot more functions for geometry types than for geography types which may influence your decision. Also see ST_DistanceSpheroid for another possibility for calculating distance from Lon/Lat coordinates.
To start with, I'd store your points as 'geography' to simplify your experiments. Your distances will then be 'great circle' calcs in metres and you won't have to worry about projections initially.