input geometry has unkown(0) geometry (Although st_transform is used) - postgresql

I have 2 tables:
A table with 3 fields:
id (text)
geom (geometry)
select ST_SRID(geom)
from A
where geom is not null
result: 32636
B table with 2 fields:
name (text)
geom (geometry)
select ST_SRID(geom)
from B
where geom is not null
result: 0
A.geom contains polygons
B.geom contains points
I want to get all the distances between A.id, A.geom and B.geom.
I tried with:
select id, st_distance(a.geom, ST_Transform(b.geom, 32636)) as dist
from A as a, B as b
where a.geom is not null
group by id, a.geom, b.geom
order by dist desc
But I'm getting error:
"input geom has unkown(0) SRID"
How can it be if I'm using ST_Transform ?
How can I fix it ?

The error message is talking about the SRID of the argument to ST_Transform, which is 0. The message means that the function has no idea in which coordinate system the point is, so it cannot transform it to another coordinate system.
The documentation says:
ST_Transform is often confused with ST_SetSRID. ST_Transform actually changes the coordinates of a geometry from one spatial reference system to another, while ST_SetSRID() simply changes the SRID identifier of the geometry.
That seems to be the case here.
You should probably use ST_SetSRID to interpret b.geom in SRID 32636.

Related

How to fix 'BOOM! Could not generate outside point' error when using ST_Distance_Spheroid with different SRS in PostGIS

I am trying to calculate the nearest feature distance from a point using PostGIS ST_Distance_Spheroid function.
Case 1:
The point and the feature collection are in the same SRS and I am expecting the distance to be in meters.
Here is my query:
SELECT
name,
ST_DistanceSpheroid(geom, ST_GeomFromText('POINT(-2.0363502486833616 52.688988284010456)', 4326), 'SPHEROID["WGS 84",6378137,298.257223563]' ) AS distance_m
FROM green_belt
ORDER BY geom <-> ST_GeomFromText('POINT(-2.0363502486833616 52.688988284010456)', 4326)
LIMIT 1;
The above query is working as expected. Here is the result:
Case 2:
When the SRS are different for the point and the feature collection, I am using the below query:
SELECT
name,
ST_DistanceSpheroid(geom, ST_Transform(ST_GeomFromText('POINT(-2.0363502486833616 52.688988284010456)', 4326), 27700), 'SPHEROID["WGS 84",6378137,298.257223563]' ) AS distance_m
FROM aonb
ORDER BY geom <-> ST_Transform(ST_GeomFromText('POINT(-2.0363502486833616 52.688988284010456)', 4326), 27700)
LIMIT 1;
But in this case, I am getting an error:
ERROR: BOOM! Could not generate outside point!
CONTEXT: SQL function "st_distance_spheroid" statement 2
SQL state: XX000
I even tried by transforming the coordinates and use it in the first query to get the distance:
SELECT
name,
ST_DistanceSpheroid(geom, ST_GeomFromText('POINT(357980.44 331724.97)', 27700), 'SPHEROID["Airy 1830",6377563.396,299.3249646]' ) AS distance_m
FROM aonb
ORDER BY geom <-> ST_GeomFromText('POINT(357980.44 331724.97)', 27700) LIMIT 1;
Even with this query, I got the same error
ERROR: BOOM! Could not generate outside point!
SQL state: XX000

Recursive PostGIS query

I am trying to transform all the roundabouts in a city into simple intersections/crossroads (o -> +). As I am using OpenStreetMap for the initial topology, some roundabouts are not a circle but just the segments of the circle (Ex: https://www.openstreetmap.org/#map=18/43.34516/-8.41536).
In practice the problem is that I need the centroid of each roundabout and I get it almost in all cases but sometimes I get several centroids for the same roundabout (centroids of the arches, no the full roundabout).
I have achieved this:
select f.osm_id as fid, (select ST_CENTROID(ST_Buffer(ST_UNION(way),1)) as r_geom
from planet_osm_line d
where st_intersects(f.way, d.way) and junction = 'roundabout') as rotonda
from planet_osm_line f
where junction like 'roundabout';
But this does not resolve the problem, it only reduces it. I am not getting the full circle, just bigger segments of it.
So I guess I need a recursive query in order to do this until the number of geometries retrieved remains the same (the full circle). Any ideas about how to build this query?
I was looking for something like this (hope it helps others in need):
create table no_roundabouts as
with recursive roundabout(geom) as (--Recursive function to build closed circled roundabouts even with roundabouts mapped as differents arches.
SELECT ST_TRANSFORM(way,3857)
FROM planet_osm_line ways --Get all segments tagged as 'roundabout'
WHERE ways.junction = 'roundabout'
UNION ALL
SELECT ST_TRANSFORM(ST_UNION(ways.way, roundabout.geom),3857)
FROM roundabout, planet_osm_line ways -- Compose segments building greater arches of the roundabout until we have the full circle (My_segment + a touching segment that is no contained in my segment)
WHERE ways.junction = 'roundabout' and ST_INTERSECTS(roundabout.geom, ways.way) and not ST_CONTAINS(roundabout.geom, ways.way)
)
SELECT * FROM roundabout;
alter table no_roundabouts add column id bigserial; -- Add id to each line
delete from no_roundabouts a -- Delete repeated roundabouts generated during recursion
where exists (select geom from no_roundabouts b where ST_CONTAINS(b.geom, a.geom) and b.id > a.id);
--select count(*) from no_roundabouts WHERE ST_IsClosed(geom) = false;
update no_roundabouts set geom = ST_LINEMERGE(geom) where ST_ISCLOSED(geom) is false --Force closed roundabouts
-- Query replacing roundabouts with crossroads (linking each way in and out with the centroid of the roundabout)
SELECT ST_TRANSFORM(ST_ADDPOINT(y.way, ST_CENTROID(x.geom), 0),4326)
FROM no_roundabouts x JOIN planet_osm_line y ON ST_INTERSECTS(y.way, x.geom)
WHERE y.highway is not null and ST_INTERSECTS(x.geom, st_pointn(y.way,1)) and ST_CONTAINS(x.geom, y.way) = false
UNION
SELECT ST_TRANSFORM(ST_ADDPOINT(y.way, ST_CENTROID(x.geom), -1),4326)
FROM no_roundabouts x JOIN planet_osm_line y ON ST_INTERSECTS(y.way, x.geom)
WHERE y.highway is not null and ST_INTERSECTS(x.geom, ST_POINTN(y.way,-1)) and ST_CONTAINS(x.geom, y.way) = false;

Postgis nearest coordinates

I'm trying to make a REST service that returns a list of places ordered by distance from the user coordinate. I found this query using postgis:
SELECT *
FROM your_table
ORDER BY your_table.geom <-> "your location..."
LIMIT 5;
But I'm not able to apply this to my actual database. I have a table that contains these columns:
title, address, description, latitude, longitude
all these values as Strings.
I'll be very happy if someone help me. Thx!
I dont know why, but ORDER BY <-> isnt exact. Sometime the closest link is on the 3rd position. So I get 101 element and then use distance to selected the closest one.
CREATE OR REPLACE FUNCTION map.get_near_link(
x numeric,
y numeric)
RETURNS TABLE(Link_ID int, distance int) AS
$BODY$
DECLARE
strPoint text;
BEGIN
strPoint = 'POINT('|| X || ' ' || Y || ')';
With CTE AS (
SELECT Link_ID,
TRUNC(ST_Distance(ST_GeomFromText(strPoint,4326), geom )*100000)::integer as distance
FROM map.vzla_seg S
ORDER BY
geom <-> ST_GeomFromText(strPoint, 4326)
LIMIT 101
)
SELECT *
FROM CTE
ORDER BY distance
LIMIT 5
In order to use PostGIS you have to enable the extension in the database. Ideally, you just run the CREATE EXTENSION postgis; command and it works. NOTE form the install page: DO NOT INSTALL it in the database called postgres. For more information visit the site.
Adding a geometry column (spatial data can be stored in this type of columns) to your table:
SELECT AddGeometryColumn(
'your_schema',
'your_table',
'geom', -- name of the column
4326, -- SRID, for GPS coordinates you can use this, for more information https://en.wikipedia.org/wiki/Spatial_reference_system
'POINT', -- type of geometry eg. POINT, POLYGON etc.
2 -- number of dimension (2 xy - 3 xyz)
);
UPDATE yourtable t SET t.geom = ST_SetSRID(ST_MakePoint(t.x, t.y), 4326)
-- the x and y is the latitude and longitude
Now you can use spatial queries on your table like this:
SELECT
*
FROM
your_table
ORDER BY
your_table.geom <-> ST_SetSRID(ST_MakePoint(x, y), 4326)
LIMIT 5;
NOTE: as others mentioned, below PostgreSQL 9.5 <-> isn't always reliable.

operator does not exist: geography <-> geography

I've postgresql column with type
geography(Point,4326)
And I've inserted some rows to it using
POINT(LONG LAT)
That data have been inserted successfully and I can retrieve it with no problems, now I want to get the nearest entries to a specific point using the following query
SELECT "cafes".* FROM "cafes" ORDER BY "latlng" <-> (SELECT latlng FROM cafes WHERE id = '3') LIMIT 1
But I'm getting the following error
ERROR: operator does not exist: geography <-> geography
LINE 1: ...es".* FROM "cafes" ORDER BY "latlng" <-> (SELEC...
^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
The <-> "distance between" operator applies to PostgreSQL geometric data types, not to the PostGIS geography data type. With the geography data type you can use the PostGIS function ST_Distance() and find the minimum value.
WITH this_cafe (latlng) AS (
SELECT latlng FROM cafes WHERE id = '3'
)
SELECT cafes.*, ST_Distance(cafes.latlng, this_cafe.latlng, 'false') AS dist
FROM cafes, this_cafe
ORDER BY dist ASC
LIMIT 1
Note that the third argument useSpheroid to the function is set to false which will make the function much faster. It is unlikely going to affect the result because cafes tend to lie close to each other.
This assumes that there is only 1 cafe with id = 3. If there could be more, then restrict the CTE to return just 1 row.

function st_intersects() does not exist using PostgreSQL 9.3

I have a table as shown below with three columns.
Table: geomet
create table geomet
(
cola float,
colb float,
geopath geometry
);
Insertion of records:
insert into geomet values('12.32232442','43.2324535',point(12.32232442,43.2324535)::geometry);
I have this:
select * from geomet;
cola colb geopath
---------------------------------------------------------------------
12.32232442 43.2324535 01010000004F34D5B407A528409D2B4A09C19D4540
Note: I need to find the Intersect of column geopath in my table as shown above. I have also installed PostGIS.
So I have tried this:
Try 1:
SELECT ST_Intersects(geopath) from geomet;
Got an error:
ERROR: function st_intersects(geometry) does not exist
Try 2:
SELECT ST_Intersects(cola,colb) from geomet;
Got an error:
ERROR: function st_intersects(double precision, double precision) does not exist
ST_Intersects requires two geometries or two geometry fields, as you are checking for the intersection between one geometry and another or one set and another set.
SELECT ST_Intersects(geomA, geomB) FROM some_table;
or
SELECT a.id., b.id, ST_Intersects(a.geom, b.geom)
FROM table a, table b
WHERE a.id > b.id;
will give you all the pairwise intersection between two tables. Obviously, you can use ST_Intersects in a where clause in a similar fashion, to only return rows where the records from two different tables intersect.