How to get coordinates of a bounding box at a certain distance from a point in postGIS? - postgis

My goal is to define a bounding box of a circle of a given radius built around a point in postGIS.
Point, extent are ok but when I do this:
select ST_AsGeoJSON( st_extent( st_buffer( ST_SetSRID(ST_MakePoint(11.0120, 49.5897), 4326), 6000 ) ) );
I get
{"type":"Polygon","coordinates":[[[-5988.988,-5950.4103],
[-5988.988,6049.5897],
[6011.012,6049.5897],
[6011.012,-5950.4103],
[-5988.988,-5950.4103]]]}
when I was expecting something along the lines of (
{"type":"Polygon","coordinates":[[[10.929017, 49.535753],
[10.929017, 49.643646],
[11.094983, 49.643646],
[11.094983, 49.535753],
[10.929017, 49.535753]]]}
(handmade GeoJSON - might contain errors)
So - how do I get the postGIS SQL to output geographical coordinates instead of what looks like geometry?

If geometry is passed into ST_Buffer, then the second argument is degrees, not meters. To use meters for the second argument, cast the first argument to geography. Then cast it back to geometry for use with extent:
select
ST_AsGeoJSON(
st_extent(
st_buffer(
ST_SetSRID(
ST_MakePoint(11.0120, 49.5897),
4326
)::geography,
6000
)::geometry
)
);

Related

Drawing a bézier curve over the equator

I'm attempting to draw a very long line from one point to another. ST_Project seems to give me the correct point to draw to, but when I use ST_MakeLine the line doesn't move east immediately from my starting point, and as such doesn't create the bézier curve I'd be expecting, but rather an arch.
In Google Maps if you draw a line using their measuring tool travelling 90° from the starting point, then it creates the expected bézier curve:
Whereas if I export my line to KML and import it into Google Maps, the line is more of an arch:
I'm using the following SQL to create my points and draw the two lines:
SELECT
ST_AsKML(
ST_Transform(
ST_Segmentize(
ST_MakeLine(
ST_Transform(
ST_SetSRID(ST_MakePoint(-0.3856949, 51.6443612), 4326),
953027
),
ST_Transform(
ST_SetSRID(
ST_AsText(
ST_Project(
ST_MakePoint(-0.3856949, 51.6443612),
2.00151e+07,
radians(90.0)
)
),
4326
),
953027
)
),
100000
),
4326
)
);
I think I've answered my own question by using explicit geometry types and NOT using ST_Segmentize as that function exists to create great circle arcs, which in this case is not what I wanted. As far as I understand it, great circle arcs are the shortest distances, such as aviation routes.
Using the below code I can create the bézier curves seen on Google Maps measuring tool:
SELECT
name,
ST_Distance(
ST_SetSRID(ST_MakePoint(0.1278, 51.5074), 4326),
area
) AS distance
FROM
countries
WHERE
(
ST_Intersects(
area,
ST_SetSRID(
ST_MakeLine(
ST_SetSRID(ST_MakePoint(0.1278, 51.5074), 4326) :: geometry,
ST_Project(
ST_SetSRID(ST_MakePoint(0.1278, 51.5074), 4326) :: geometry,
2.00151e+07,
pi() * 90 / 180.0
) :: geometry
),
4326
)
)
)
ORDER BY
ST_Distance(
ST_SetSRID(ST_MakePoint(0.1278, 51.5074), 4326),
area
);

Retrieving raster data by geographic location using Landsat and PostGIS

The project I am working on requires that I retrieve Landsat raster data at specific geographic (lon/lat) locations. After sifting through some tutorials and experimenting with GDAL, PostGIS, and QGIS, I successfully imported a GeoTIFF Landsat image into a PostGIS raster table and accessed values by geographic location from that table. However, there were a few issues in the result:
I do not understand the coordinate system being used by QGIS in its interface, as they range in the hundred thousands
The raster loaded into QGIS off the coast of Spain, rather than on top of Maine, USA as it was supposed to.
Here's some information about my process. I am fairly new to GIS in general, so I am almost certain theres a blatant error to be found here:
Download Landsat 8 GeoTIFF file from USGS GloVis
Rename the band 5 image to something more friendly to command ninja with.
Create postgres database for raster tables and run CREATE EXTENSION postgis;
Run gdalinfo LSSampleB5.TIF, printing the following output:
Driver: GTiff/GeoTIFF
Files: LSSampleB5Test2.TIF
Size is 7871, 7971
Coordinate System is:
PROJCS["WGS 84 / UTM zone 19N",
GEOGCS["WGS 84",
DATUM["WGS_1984",
SPHEROID["WGS 84",6378137,298.257223563,
AUTHORITY["EPSG","7030"]],
AUTHORITY["EPSG","6326"]],
PRIMEM["Greenwich",0,
AUTHORITY["EPSG","8901"]],
UNIT["degree",0.0174532925199433,
AUTHORITY["EPSG","9122"]],
AUTHORITY["EPSG","4326"]],
PROJECTION["Transverse_Mercator"],
PARAMETER["latitude_of_origin",0],
PARAMETER["central_meridian",-69],
PARAMETER["scale_factor",0.9996],
PARAMETER["false_easting",500000],
PARAMETER["false_northing",0],
UNIT["metre",1,
AUTHORITY["EPSG","9001"]],
AXIS["Easting",EAST],
AXIS["Northing",NORTH],
AUTHORITY["EPSG","32619"]]
Origin = (318285.000000000000000,5216715.000000000000000)
Pixel Size = (30.000000000000000,-30.000000000000000)
Metadata:
AREA_OR_POINT=Point
Image Structure Metadata:
INTERLEAVE=BAND
Corner Coordinates:
Upper Left ( 318285.000, 5216715.000) ( 71d23'37.53"W, 47d 4'44.12"N)
Lower Left ( 318285.000, 4977585.000) ( 71d18' 9.77"W, 44d55'42.53"N)
Upper Right ( 554415.000, 5216715.000) ( 68d16'58.41"W, 47d 6' 6.11"N)
Lower Right ( 554415.000, 4977585.000) ( 68d18'36.69"W, 44d56'58.62"N)
Center ( 436350.000, 5097150.000) ( 69d49'20.56"W, 46d 1'29.87"N)
Band 1 Block=7871x1 Type=UInt16, ColorInterp=Gray
I interpretted this output as EPSG 4326 format (which may be my crime), so I ran the following command to import the GeoTIFF as a PostGIS raster:
raster2pgsql -s 4326 -I LSSampleB5.TIF -F -t 50x50 -d | psql -U postgres rastertest
This successfully imported a new table. I then used QGIS to get a visual intuition of what was going on.
Under Database -> DB Manager -> PostGIS -> rastertest -> public I added my lssampleb5 to the canvas.
I created a new XYZ Connection in QGIS to add Google satillite hybrid images for reference. The url I used was https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z} with min and max zoom of 0 and 19 respectively.
Here is where I took note of the fact that the lssample layer landed off the coast of Spain on the Google Hybrid map.
I made sure both layers were on EPSG 4326 projection, no change.
Not too discouraged to move on, I tried a database query to get a single pixel value. Since my sample data landed near Spain, I used QGIS to sample a valid coordinate pair near there for the query. The query was:
SELECT rid, ST_Value(rast, 1, ST_SetSRID(ST_Point(448956,5041439), 4326)) as b5
FROM lssampleb5
WHERE ST_Intersects(rast, ST_SetSRID(ST_Point(448956,5041439), 4326)::geometry, 1);
This returned a valid row ID and an ST_VALUE of 5776. Trying coordinates outside the range displayed by QGIS resulted in no returned entries, which isn't unexpected.
So, first of all, I do not know what QGIS is using for its coordinate system. It's definitely not longitude and latitude in a raw form, but from my understanding, EPSG 4326 is supposed to be a geographic projection.
Second, I don't know why QGIS is misplacing the Landsat scene in the wrong place, or where in the process the scene was not transformed properly.
Join us at GIS SE, that´s the place for GIS related Q/A!
To help you out here:
Indeed, your crime was the CRS. The top level PROJCRS tag is the
key here, it reads out "WGS 84 / UTM zone 19N" from the data, with
the EPSG reference at the bottom (AUTHORITY["EPSG","32619"]]).EPSG:32619 is a UTM projected CRS based on the WGS84 geoid (datum) and with units in meter, defined as the projected distance to the corresponding reference meridians (Easting) and the equator (Northing). Since you defined the wrong CRS during import (i.e. EPSG:4326), the inherent coordinate values of the raster were treated as degree´s and the whole thing placed to the other end of the world. Run UpdateRasterSRID (SELECT UpdateRasterSRID(<shema_name>, <your_raster_table>, rast, 32619);) to set the raster's metadata to the correct CRS and reload the layer.
As for QGIS: it uses the CRS that you tell it to use. QGIS comes with a very handy on-the-fly reprojection feature (OTF, check out the general man page on 'working with projections' here) that lets you define an arbitrary CRS for your data to be projected and displayed (i.e. it reprojects the data's CRS into the defined one in memory, the data's metadata stays untouched).You can find the quick link button to the OTF settings in the bottom right corner of the GUI; set it to your desired SRID (e.g. 4326) (you´ll notice how the visual representation of your data changes according to the chosen projection. also the displayed coordinates will use the CRS units, e.g. decimal degrees for WGS84).

how to generate a query for bring points in a radius in postgis

My question is how to calculate the radius from a point for all the locations that are in this radius? I am trying but always the query finds locations out site from the radius. This is an example:
the query I am using is:
SELECT *
FROM "Property"
WHERE "Property"."DeletedAt" IS NULL
AND ((ST_DWithin(ST_SetSRID(ST_Point(43.628123412124616, -116.19140625), 4326)::geography, ST_SetSRID(ST_Point("Latitude", "Longitude"), 4326)::geography, 25730.9, true)))
ST_POINT takes longitude then latitude, so you should swap the two parameters. see the doc

PostGIS ST_Expand point by meters and bounding box

I don't think something is right want max and min lat long of the 100 meter buffer.
SELECT ST_Asgeojson(
ST_Expand(
ST_GeomFromEWKT('SRID=4326;POINT(-88.33 36.33)')
,100
)
);
Think it is calculating by 100 degrees of lat and long.
This gis.se question shows what I'm wanting to do. Answer 5 graphically depicts what I'm wanting to do.
I'm trying to get the
coordinates: [
[-80.425, 46.437],
[-71.516, 46.437],
[-71.516, 37.936],
[-80.425, 37.936]`
to add it to the map.
Yes, of course... As in documentation of ST_Expand
Units are in the units of the spatial reference system in use denoted
by the SRID.
EPSG:4326 is in degrees so it's exanding by 100 degrees.
I suggest you use ST_Buffer function with geography datatype:
SELECT ST_Asgeojson(ST_Buffer((ST_GeomFromEWKT('SRID=4326;POINT(-88.33 36.33)'))::geography,100));
And if you need rectangle you have to add ST_Envelope with geography::geometry
SELECT ST_Asgeojson(ST_Envelope(ST_Buffer((ST_GeomFromEWKT('SRID=4326;POINT(-88.33 36.33)'))::geography,100)::geometry));
If you need to use this in select from table you might need to reproject your geometry because cast ::geography needs a LatLon CRS, so it'll look like this:
SELECT ST_Asgeojson(ST_Envelope(ST_Buffer((ST_Transform(x.the_geom,4326)::geography,100)::geometry));

I tried all ways, but still my area is calculated wrongly in Postgis

I created a very simple polygon in the middle of Germany to demonstrate my problem.
You can visualize it in geojsonlint using the following GeoJSON
{"type":"Polygon","coordinates":[[
[10.439844131469727,51.17460781257472],
[10.430574417114258,51.1753073564544],
[10.429565906524658,51.17179607723465],
[10.438792705535889,51.170706315523866],
[10.439372062683105,51.17267055874809],
[10.43975830078125,51.17439256616884],
[10.439844131469727,51.17460781257472]]]G}
When calculating the surface with online tools (e.g. http://www.daftlogic.com/projects-google-maps-area-calculator-tool.htm, but I tried several),
I get the following numbers (these are based on a similar drawing of the polygon, but not the exact same one, as I couldn't copy it over to these tools):
276583.39 m²
0.28 km²
68.35 acres
27.66 hectares
2977118.86 feet²
0.08 square nautical miles
Now I want to calculate these areas using POSTGIS, but I always get wrong and not matching numbers.
First I started without transformation using the examples given here:
http://postgis.net/docs/ST_Area.html
SELECT ST_Area(the_geom) As sqft, ST_Area(the_geom)*POWER(0.3048,2) As sqm
FROM (SELECT ST_GeomFromText('
POLYGON ((51.17460781257472 10.439844131469727,
51.1753073564544 10.430574417114258,
51.17179607723465 10.429565906524658,
51.170706315523866 10.438792705535889,
51.17267055874809 0.439372062683105,
51.17439256616884 10.43975830078125,
51.17460781257472 10.439844131469727))',4326) ) As foo(the_geom);
--> sqft = 3.52643124351653e-05 and sqm = 3.27616182873666e-06
How can I interprete these numbers?
Then I tried to transform it to WGS 84 / UTM zone 33N 32633
SELECT ST_Area(the_geom) As sqft, ST_Area(the_geom)*POWER(0.3048,2) As sqm
FROM (SELECT ST_Transform(ST_GeomFromText('
POLYGON ((51.174661624019286 10.440187454223633,
51.17067940750161 10.438899993896484,
51.17197097486416 10.429544448852539,
51.17536116708255 10.430488586425781,
51.174661624019286 10.440187454223633))',4326),32633) ) As foo(the_geom);
--> sqft = 662918.939349234 and sqm = 61587.1847391195
But even these numbers don't come close.
The coordinates of the polygon were accidentally loaded as lat,lon instead of lon, lat.
http://postgis.net/2013/08/18/tip_lon_lat
says
In spatial databases spatial coordinates are in x = longitude, and y = latitude
I converted the coordinates into EPSG: 31467, see epsg:31467 which is projected to meters and applies to the area of Germany covered by your geometry.
select st_area(st_transform(st_setsrid(st_geomfromtext('POLYGON((10.439844131469727
51.17460781257472,10.430574417114258 51.1753073564544,10.429565906524658
51.17179607723465,10.438792705535889 51.170706315523866, 10.439372062683105
51.17267055874809, 10.43975830078125 51.17439256616884, 10.439844131469727
51.17460781257472))'),4326),31467));
and got the answer: 274442.27 m2 which is within 0.007% of your original answer.
Measurements are usually more accurate in projected coordinate systems that use a geoid appropriate to that region. If you run this query on the spatial reference system table in Postgis for that projection:
select * from spatial_ref_sys where srid=31467;
you will see some more details, such as the fact that it uses the Bessel 1841 spheroid.
EDIT: your original geojson has coordinates in x/y, but for some reason you flipped them when putting them into Postgis.

Resources