Получить длину подсегмента «linestring» в пределах заданной области (используя ST_DWithin)

#postgis #openstreetmap

#postgis #openstreetmap

Вопрос:

Мне нужно получить длину фрагмента геометрического объекта linestring внутри круга (точка радиус).

В настоящее время я использую ST_DWithin функцию, но, к сожалению, она возвращает полный объект, а не часть объекта внутри области. Действительно, изменение радиуса (от 100 до 70) не изменяет полученную длину.

 osm_data=# select highway, st_length(way) from planet_osm_line where ST_DWITHIN(ST_Transform(way,4326),ST_GeomFromText('POINT(4.1884918 51.144580)',4326)::geography,100) and highway is not null;
   highway    |    st_length     
-------------- ------------------
 motorway     | 5079.24632083105
 unclassified | 1110.56834915499
 motorway     | 1499.83459080537
(3 rows)

osm_data=# select highway, st_length(way) from planet_osm_line where ST_DWITHIN(ST_Transform(way,4326),ST_GeomFromText('POINT(4.1884918 51.144580)',4326)::geography,70) and highway is not null;
   highway    |    st_length     
-------------- ------------------
 motorway     | 5079.24632083105
 unclassified | 1110.56834915499
 motorway     | 1499.83459080537
(3 rows)
  

Ответ №1:

ST_DWithin используется для выбора геометрий, которые по крайней мере частично находятся на указанном расстоянии от контрольной точки.

Чтобы вычислить фактическую длину (или площадь для полигонов) внутри, вам нужно будет вычислить пересечение.

 select highway, 
   st_length(way) full_length,   
   st_length(
     ST_INTERSECTION(
        ST_Transform(way,4326)::geography,
        ST_BUFFER(
          ST_GeomFromText('POINT(4.1884918 51.144580)',4326)::geography,
         100)
      )
   )
  from planet_osm_line 
  where
    ST_DWITHIN(
      ST_Transform(way,4326)::geography,
      ST_GeomFromText('POINT(4.1884918 51.144580)',4326)::geography,100) 
    and highway is not null;
  

Чтобы оптимизировать этот запрос, вы бы использовали

 WITH buff as (
   SELECT ST_BUFFER(
            ST_GeomFromText('POINT(4.1884918 51.144580)',4326)::geography, 
            1000) as geog)  
select highway, 
   st_length(way) full_length,   
   st_length(
     ST_INTERSECTION(
        ST_Transform(way,4326)::geography,
        buff.geog
      )
   )
from osm.osm_line
    INNER JOIN buff
        ON ST_DWITHIN(
          ST_Transform(way,4326),
          buff.geog,
          1000) 
where highway is not null;
  

Пожалуйста, обратите внимание, что буфер является лишь приближением к окружности, поэтому результат может быть немного отклонен