简体   繁体   中英

Postgis - ST_within didn't do what I want. How to find a point in a hollow area?

See the screen print.

I ran a spatial query in Postgis to return the electoral constituency (area) that a point on the map lies in. The query uses a ST_within function where the point is within a polygon.

As you can see from the print, the point is not actually 'in' the polygon area of York Outer although technically you might say it's 'within' it, or at least Postgis thinks so. The point would actually lie in York Central.

I'm sure Postgis actually returns both but since I only fetch the first record from the cursor, this is what I see.

A point can only be in one electoral constituency at a time and this query has returned the wrong one or rather I asked the wrong question of the database.

Which function should I be using to ensure I always return the correct area for a point where it's possible the area may have a hollow interior or be a strange shape?

ST_within 允许非重叠点

Thanks

Phil

This should work as you described it. Maybe something is wrong with the data? Could you provide a small repro, with polygon / point data?

Also, a somewhat common reason for such problems is not valid GIS data. You can check the polygon shape with PostGIS's ST_IsValid function. If the data is not valid, different tools might interpret it in different ways, and how GIS data is drawn might not match what PostGIS thinks this data represents, causing more confusion.

Here is a simple repro showing it works as you expect it to work, with point inside the outer polygon's hole only st_within the inner polygon, not the outer one:

select st_astext(point), name 
from 
  (select 
       'outer' as name, 
       st_geomfromtext('polygon((0 0, 30 0, 30 30, 0 30, 0 0), (10 10, 20 10, 20 20, 10 20, 10 10))') g
  union all 
  select 
      'inner' as name, 
       st_geomfromtext('polygon((10 10, 20 10, 20 20, 10 20, 10 10))') g
  ) shapes
cross join
  (select st_geomfromtext('point(15 15)') point
   union all
   select st_geomfromtext('point(5 5)') point
  ) points
where st_within(point, g)

My results are

1   POINT(5 5)     outer
2   POINT(15 15)   inner

Considering your polygons and query are the way you described, it should work without any problems. Consider the following geometries ..

在此处输入图片说明

.. you see that the point lies only inside the inner polygon. If you perform a query with ST_Within giving the coordinates of the point, you should get only the inner polygon:

WITH j (geom) AS (VALUES 
  ('POLYGON((35 10, 45 45, 15 40, 10 20, 35 10),(20 30, 35 35, 30 20, 20 30))'),
  ('POLYGON((26.88 31.08,30.57 31.08,30.57 28.49,26.88 28.49,26.88 31.08))'))
SELECT * FROM j
WHERE ST_Within('POINT(28.46 28.64)',j.geom)

在此处输入图片说明

However, if your query is somehow using the BBOX of the polygons instead of their area, you will indeed get the outer polygons as well, eg:

WITH j (geom) AS (VALUES 
  ('POLYGON((35 10, 45 45, 15 40, 10 20, 35 10),(20 30, 35 35, 30 20, 20 30))'),
  ('POLYGON((26.88 31.08,30.57 31.08,30.57 28.49,26.88 28.49,26.88 31.08))'))
SELECT * FROM j
WHERE ST_Within('POINT(28.46 28.64)',j.geom::GEOMETRY::BOX2D)

在此处输入图片说明

Consider adding a data sample and the query to your question. Hopefully it helps you debug your code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM