Menemukan Geometri terdekat di PostGIS

16

Saya telah melihat-lihat fungsi "API" PostGIS, dan saya perhatikan bahwa kebanyakan dari mereka mengambil dua elemen untuk membandingkan. Misalnya, fungsi ST_Distance mengambil dua elemen geometri / geografi untuk menemukan jarak.

Tidak ada fungsi untuk melakukan sesuatu seperti: "Diberi geometri G, beri saya geometri GClosest terdekat di Tabel T di mana G.id <> GClosest.id"

Saya menyadari bahwa saya bisa menulis fungsi PL / PgSQL untuk beralih di atas tabel dan memanggil ST_Distance pada setiap elemen, tapi saya berharap ada solusi yang lebih baik, lebih efisien,.

Jmoney38
sumber
1
Jika Anda tertarik pada jarak ke geometri terdekat, periksa gis.stackexchange.com/questions/11979/…
underdark
beri tahu saya jika saya mengerti benar ... Anda menginginkan fitur berikutnya yang memiliki jarak yang sama daripada yang terdekat?
falcacibar

Jawaban:

7

Pertanyaan Anda juga dapat dijawab oleh satu (meskipun kompleks) permintaan seperti berikut ini yang mengembalikan seluruh catatan dan jarak ke geometri referensi. Harap dicatat bahwa jika lebih dari satu catatan cocok dengan jarak min, semuanya dikembalikan.

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;

Saya telah menguji permintaan ini pada tabel alamat dan berhasil. Dalam kueri di atas saya mencari titik terdekat dengan id = 3.

unicoletti
sumber
Ini adalah informasi yang bagus - terima kasih ... Saya mengerti fungsi agregat min (..) menurut definisi, tapi saya bingung bagaimana ini digunakan dalam contoh Anda. st_distance (X, Y) mengambil dua jenis geometri dan mengembalikan jarak di antara mereka, yang merupakan nilai tunggal. Mengapa Anda kemudian memanggil fungsi agregat pada hasil nilai tunggal itu? Mungkin saya salah menafsirkan pernyataan pilih di dalam ...
Jmoney38
Grup oleh adalah pada geometri ga yang merupakan konstanta untuk seluruh hasil yang ditetapkan (ingat ga dipilih oleh id = 3) sehingga pada dasarnya tidak melakukan apa-apa. Itu hanya trik agar geometri ga tersedia di st_distance kueri luar tanpa bergabung dengan tabel dua kali lagi. Hari ini saya berpikir bahwa mungkin saya bisa lolos dengan permintaan innner sama sekali dengan menggunakan klausa partisi . Itu juga harus meningkatkan kinerja. Saya akan mencobanya dan memberi tahu Anda.
unicoletti
Sayangnya fungsi-fungsi jendela diperkenalkan pada 8.4 dan sekarang saya tidak memiliki akses ke server yang memiliki postgis dan versi itu sehingga saya tidak dapat menguji permintaan yang ditulis ulang dengan klausa partion.
unicoletti
7

George MacKerron telah menulis fungsi Tetangga Terdekat sederhana yang menurut saya cukup berguna. Fungsi ini mengembalikan ID tetangga terdekat ke fitur yang diberikan:

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;

Contoh penggunaan:

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

... memilih simpul terdekat di tabel nw_node untuk setiap entri di my_point_table.

Ada juga fungsi yang lebih umum di situs GIS Boston .

underdark
sumber
Saya lebih peduli dengan cara membuat kueri 1: N kueri dalam arti yang lebih umum. Misalnya, alih-alih menemukan elemen terdekat ke geometri G, saya mungkin ingin menemukan elemen pertama yang tumpang tindih G. Terima kasih atas informasinya, terlepas dari itu. Tautan ke Boston GIS sangat berguna! Saya sudah mencetak beberapa lembar cheat :-)
Jmoney38
Mungkin Anda bisa menguraikan kembali pertanyaan Anda untuk membuatnya sedikit lebih jelas, @ Jmoney48. Jadi Anda tidak tertarik dengan masalah tetangga terdekat secara khusus tetapi lebih pada bagaimana membandingkan satu geometri dengan semua geometri dalam tabel?
underdark
SELALU menggunakan fungsi generik dari situs GIS Boston, yang sederhana sangat lambat untuk tabel besar dan upaya untuk menerapkannya tidak lebih besar.
Vladtn