How to display LAT/LONG of polygon? - postgresql

I have a table with geom field (type: geometry)
I want to display the values of the polygon in lat/long.
How can I do it ?
I saw this post:
https://gis.stackexchange.com/questions/95373/convert-geometry-to-latitude-longitude-using-postgis-st-transform/95376
but the functions ST_X, ST_Y only works on POINT and not on POLYGON.
How can I display the geom field (which contains polygon) in lat/long format ?

Depending on the output you want, it might very well be that ST_ASGEOJSON already does everything you want, but otherwise, you can use ST_DUMPPOINTS to get all the individual points of the polygon.
SELECT polygon.id,
( SELECT ARRAY_AGG(ST_Y(geom ORDER BY path))
FROM ST_DUMPPOINTS(polygon) AS points ) as latitudes,
( SELECT ARRAY_AGG(ST_X(geom ORDER BY path))
FROM ST_DUMPPOINTS(polygon) AS points ) as longitudes
FROM polygons
would return ordered lists of latitudes and longitudes per polygon.
If you want to combine, them, use JSON:
SELECT polygon.id,
( SELECT ARRAY_AGG(
JSON_BUILD_OBJECT(
'latitude', ST_Y(geom),
'longitude', ST_X(geom)
) ORDER BY path)
)
FROM ST_DUMPPOINTS(polygon) AS points )
FROM polygons

Related

PostGIS and coordinates, determinate if a point is inside a multipolygon

I have the coordinates: -48.54367281530538 -15.91180231568948
I need to know if these coordinates belong to my multpolygon
select boolean st_contains(st_geomfromtext('POINT(-48.54367281530538 -15.91180231568948)',4326), st_geomfromkml(a.geom))
from "LIM_Municipio_A" as a
where nome ilike 'alexânia';
My Table:
The doc says:
boolean ST_Contains(geometry geomA, geometry geomB);
Geometry A contains Geometry B if [...]
So you would have to use the polygon first, then the point.
select st_contains(
st_geomfromkml(a.geom),
st_geomfromtext('POINT(-48.54367281530538 -15.91180231568948)',4326)
)
from "LIM_Municipio_A" as a
where nome ilike 'alexânia';

Store circles in Postgres geometry field

Ideally it would be something like this, but WKT doesn't have circle type.
ST_GeomFromText('CIRCLE(10 20, 10)',4326)
Although, circle type is listed among geometric types,
circle <(x,y),r> (center point and radius)
I wonder if it's possible to use circle type directly in sql:
update <table>
set the_geom = circle '((10, 20),10)'::geometry
where id = <id>;
But it says SQL Error [42846]: ERROR: cannot cast type circle to geometry.
Using ST_Buffer for storing circles is a kludge so I don't want to use it.
Alternative solution could be jsonb + geojson, but it doesn't support circles either.
UPD: There is my table structure. Currently I'm using longitude/latitude/radius, but I'd like to use either geo_json or the_geom. How could GeoJSON and WKT not support a circle?
CREATE SEQUENCE my_table_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
CREATE TABLE my_table (
id INT NOT NULL,
longitude NUMERIC(10, 7) DEFAULT NULL,
latitude NUMERIC(10, 7) DEFAULT NULL,
radius INT DEFAULT NULL,
geo_json JSONB,
the_geom Geometry DEFAULT NULL, PRIMARY KEY(id)
);
Circle is native for postgresql as you can see on the manual documentation.
Geometry is a type related to PostGis Extension, and doesnt have CIRCLE but use polygons with lot of points instead.
Function starting with ST_ are also Postgis functions and work only with Postgis geometry or geography data type
SQL DEMO:
create table points ( p POINT not null);
create table lines ( l LINE not null);
create table circles ( c CIRCLE not null);
insert into points (p) values ( POINT(1.2, 123.1) );
insert into lines (l) values ( LINE(POINT(1.2, 123.1), POINT(-5, -123)) );
insert into circles (c) values ( CIRCLE(POINT(1.2, 123.1), 10) );
SELECT * FROM points;
SELECT * FROM lines;
SELECT * FROM circles;
The GIST index allows you to work efficiently with circles. If that's the only thing you intend to store in this table, then you can do it like this:
CREATE TABLE my_table (
id INT NOT NULL,
longitude NUMERIC(10, 7) DEFAULT NULL,
latitude NUMERIC(10, 7) DEFAULT NULL,
radius INT DEFAULT NULL,
geo_json JSONB
);
CREATE INDEX idx_my_table ON my_table USING GIST ( circle( point( latitude, longitude ), radius ));
As others have pointed out, you cannot mix this table with GEOMETRY types, which are incompatible.
In order to utilize the index above, you must express your WHERE criteria in similar terms: circle( point( latitude, longitude ), radius ) or '<( latitude, longitude ), radius >'::circle and use the operators that GIST knows about ... which are listed below. I'm aware that projecting the Euclidian shape of a circle onto a non-Euclidian spherical geometry has limitations, but for index purposes it should work OK with care.
https://www.postgresql.org/docs/current/gist-builtin-opclasses.html

What is an efficient way to convert a set of ordered latitude longitude pairs into a Linestring in PostGIS?

I can convert it into WKT and then to a Linestring but I think there are more efficient ways to do it.
Presuming your data looks like this:
You may convert the set of ordered longitude/latitude pairs into linestrings like this:
SELECT ST_AsText(ST_MakeLine(q.f, q.t)) FROM
(SELECT (SELECT ST_MakePoint(c.long_from, c.lat_from) AS f),
(SELECT ST_MakePoint(c.long_to, c.lat_to) AS t)
FROM lonlatset c) AS q;
And here's the result:
Try to remember that it is very important to respect the proper coordinates order: first the longitude, and second the latitude!

Unit of return value of ST_Distance

I need to calculate the distance between
all buildings and
all hospitals
in a map imported from OSM.
I use following query:
SELECT building_id, hospital_id, ST_Distance(building_centroid, hospital_location)
FROM
(
select planet_osm_polygon.osm_id building_id, ST_Centroid(planet_osm_polygon.way) building_centroid
from planet_osm_polygon
where building = 'yes'
) buildings,
(
select planet_osm_point.osm_id hospital_id, planet_osm_point.way hospital_location
from planet_osm_point
where amenity = 'hospital') hospitals
I get strange results - the distance is always smaller than 1.
How can I get the to know the unit, in which these values are reported?
Update 1: Sample result:
Update 2: This query seems to work
SELECT building_id, hospital_id, ST_Distance_sphere(building_centroid, hospital_location) distance
FROM
(
select planet_osm_polygon.osm_id building_id, ST_Centroid(planet_osm_polygon.way) building_centroid
from planet_osm_polygon
where building = 'yes'
) buildings,
(
select planet_osm_point.osm_id hospital_id, planet_osm_point.way hospital_location
from planet_osm_point
where amenity = 'hospital') hospitals
ORDER BY distance
The general rule for units is that the output length units are the same as the input length units.
The OSM way geometry data has length units of degrees of latitude and longitude (SRID=4326). Therefore, the output units from ST_Distance will also have lenth units of degrees, which are not really useful.
There are several things you can do:
Use ST_Distance_Sphere for fast/approximate distances in metres
Use ST_Distance_Spheroid for accurace distances in metres
Convert the lat/long geometry data types to geography, which automagically makes ST_Distance and other functions to use linear units of metres

How can I extract some LINESTRING consisted of 3 or more POINTs to several LINESTRINGs each by 2 POINTs in PostGIS

I have to get an array of simple lines from one multipoint linestring. How can I do it?
Try this query:
SELECT MakeLine(sp,ep)
FROM (
SELECT pointn(wkb_geometry, generate_series(1, npoints(wkb_geometry)-1)) as sp,
pointn(wkb_geometry, generate_series(2, npoints(wkb_geometry) )) as ep
FROM geom_table
) as tmp;
Though this isn't very performant on larger linestrings.