Нахождение ближайшей геометрии в PostGIS

16

Я просматривал «API» функций PostGIS и заметил, что для большинства из них нужно сравнить два элемента. Например, функция ST_Distance берет два элемента геометрии / географии, чтобы найти расстояние.

Нет функции для выполнения чего-то вроде: «Учитывая геометрию G, дайте мне ближайшую геометрию GClosest в таблице T, где G.id <> GClosest.id»

Я понимаю, что мог бы написать функцию PL / PgSQL для итерации по таблице и вызывать ST_Distance для каждого элемента, но я надеюсь, что есть лучшее, более эффективное решение.

Jmoney38
источник
1
Если вас интересует расстояние до ближайшей геометрии, проверьте gis.stackexchange.com/questions/11979/…
Подземье
дайте мне знать, если я правильно понял ... вы хотите, чтобы следующая функция была на том же расстоянии, что и самая близкая?
фалькасибар

Ответы:

7

На ваш вопрос также можно ответить одним (хотя и сложным) запросом, подобным следующему, который возвращает всю запись и расстояние до базовой геометрии. Обратите внимание, что если несколько записей соответствуют минимальному расстоянию, все они возвращаются.

SELECT 
  i.*,
  md.min_distance
FROM
  address AS i, 
  (SELECT 
     ga.address_geom,
     min( ST_Distance(
            ga.address_geom,
            gb.address_geom)
        ) AS min_distance
   FROM
     address AS ga,
     address AS gb 
   WHERE 
     ga.id <> gb.id 
   AND 
     ga.id = 3
   GROUP BY 
     ga.address_geom
  ) AS md 
WHERE 
  ST_Distance( i.address_geom, md.address_geom) = md.min_distance;

Я проверил этот запрос на таблице адресов, и он работает. В запросе выше я ищу ближайшую точку к этому с id = 3.

unicoletti
источник
Это хорошая информация - спасибо ... Я понимаю агрегатную функцию min (..) по определению, но я не совсем понимаю, как она используется в вашем примере. st_distance (X, Y) принимает два типа геометрии и возвращает расстояние между ними, которое является одним значением. Почему вы тогда вызываете статистическую функцию для этого единственного значения результата? Может быть, я неверно истолковываю внутреннее утверждение выбора ...
Jmoney38
Группировка по находится на геометрии ga, которая является константой для всего набора результатов (помните, что ga выбрана с помощью id = 3), поэтому она в основном ничего не делает. Это просто хитрость, чтобы геометрия ga была доступна во внешнем запросе st_distance без повторного присоединения к таблице. Сегодня я подумал, что, возможно, мне удастся вообще обойтись без внутреннего запроса с помощью предложения раздела . Это также должно улучшить производительность. Я попробую и дам вам знать.
unicoletti
К сожалению, оконные функции были введены в 8.4, и теперь у меня нет доступа к серверу, на котором есть и postgis, и эта версия, поэтому я не могу проверить запрос, переписанный с помощью предложения partion.
unicoletti
7

Джордж МакКеррон написал простую функцию Nearest Neighbor, которая мне показалась весьма полезной. Эта функция возвращает идентификатор ближайшего соседа данной функции:

create or replace function 
  nn(nearTo                   geometry
   , initialDistance          real
   , distanceMultiplier       real 
   , maxPower                 integer
   , nearThings               text
   , nearThingsIdField        text
   , nearThingsGeometryField  text)
 returns integer as $$
declare 
  sql     text;
  result  integer;
begin
  sql := ' select ' || quote_ident(nearThingsIdField) 
      || ' from '   || quote_ident(nearThings)
      || ' where st_dwithin($1, ' 
      ||   quote_ident(nearThingsGeometryField) || ', $2 * ($3 ^ $4))'
      || ' order by st_distance($1, ' || quote_ident(nearThingsGeometryField) || ')'
      || ' limit 1';
  for i in 0..maxPower loop
     execute sql into result using nearTo              -- $1
                                , initialDistance     -- $2
                                , distanceMultiplier  -- $3
                                , i;                  -- $4
    if result is not null then return result; end if;
  end loop;
  return null;
end
$$ language 'plpgsql' stable;

Пример использования:

SELECT id, nn(pt_geom,0.00001,2,100,'nw_node','node_id','node_geom') FROM my_point_table;

... выбирает ближайший узел в таблице nw_node для каждой записи в my_point_table.

Существует также более общая функция на сайте ГИС в Бостоне .

Подземье
источник
Меня больше интересует, как создавать запросы 1: N запросов в более общем смысле. Например, вместо нахождения ближайшего элемента к геометрии G, я мог бы захотеть найти первый элемент, который перекрывает G. Спасибо за информацию, независимо. Ссылка на Бостонскую ГИС была очень полезной! Я уже напечатал некоторые шпаргалки :-)
Jmoney38
Может быть, вы могли бы перефразировать ваш вопрос, чтобы сделать его немного понятнее, @ Jmoney48. Таким образом, вы не заинтересованы конкретно в проблеме ближайшего соседа, а в том, как сравнить одну геометрию со всеми геометриями в таблице?
Подземье
ВСЕГДА используйте универсальную функцию сайта ГИС в Бостоне, простая для невероятно медленных для больших таблиц, и усилия по ее применению не больше.
Владтн