Mendeteksi jika titik ada di sisi kiri atau kanan garis di PostGIS?

16

Saya memiliki tabel linestring dan tabel poin di postgis.

Saya tahu garis terdekat ke titik tertentu. Yang perlu saya ketahui adalah "sisi" dari garis mana yang menjadi intinya. Saya kira saya harus melakukan itu dengan membuat garis tegak lurus dari titik yang diberikan ke garis (titik terdekat di garis) dan kemudian membandingkan koordinat, tetapi saya tidak tahu persis bagaimana melakukannya, dan jika itu cara yang tepat, karena garis mengubah arahnya.

Saya telah membuat gambar untuk menggambarkan tugas saya.

masukkan deskripsi gambar di sini

Garis itu sendiri berwarna hitam, arahnya ditunjukkan dengan panah hijau. Saya perlu menambahkan kolom "sisi" ke tabel titik, sehingga titik merah harus memiliki nilai "benar" dan titik biru harus memiliki nilai "kiri".

Bisakah seseorang memberikan contoh kode SQL untuk menghitung nilai "sisi" suatu titik?

mofoyoda
sumber

Jawaban:

12
select (ST_Azimuth(h.vec) - ST_Azimuth(h.seg))
from (
    select 
        ST_MakeLine(cp.p, point.geom) vec,
        ST_MakeLine(cp.p, 
            ST_LineInterpolatePoint(
                line.geom, 
                ST_LineLocatePoint(line.geom, cp.p) * 1.01)
        ) seg
        from (
            select 
                ST_ClosestPoint(line.geom, point.geom)
        ) p as cp
    ) as h

Jadi idenya adalah untuk menghitung sudut antara segmen garis terdekat, dan vektor dari titik terdekat pada garis ke titik Anda.

dapatkan poin terdekat di telepon

select ST_ClosestPoint(line.geom, point.geom)

buat vektor dari titik terdekat ke titik Anda

ST_MakeLine(cp.p, point.geom) vec

buat vektor di antara baris Anda

ST_MakeLine(
    --original point
    cp.p, 
    --find a point next to the closest point on line
    ST_LineInterpolatePoint(line.geom, 
         ST_LineLocatePoint(line.geom, cp.p) * 1.01)) seg

dapatkan perbedaan antar arah

ST_Azimuth(h.vec) - ST_Azimuth(h.seg)

Jadi kanan dan kiri akan lebih besar dari nol dan lebih rendah dari nol.

dmitry.v.kiselev
sumber
Terima kasih, sepertinya ini solusi yang bagus, tapi saya tidak suka bagian * 1.01. Bisakah titik terdekat berikutnya dari garis dipilih untuk membuat kueri ini lebih dapat diandalkan?
mofoyoda
Saya sedang berpikir untuk mendapatkan segmen terdekat tetapi tidak ada fungsi di sana. Tetapi ini adalah solusi yang lebih andal karena ST_LineInterpolate diarahkan sehingga Anda akan mendapatkan titik berikutnya ke arah garis, bukan hanya terdekat. Dimungkinkan untuk mendapatkan simpul berikutnya yang sebenarnya, tetapi itu akan mendesak Anda untuk beralih ke semua simpul dan mencari tahu apakah mereka selanjutnya di sepanjang garis atau sebelum titik terdekat di garis.
dmitry.v.kiselev
Hai Dmitry. Apakah ini akan bekerja untuk titik yang berada di luar garis jika Anda tahu apa yang saya maksud. Misalnya, bagian paling kiri atas titik merah, jika 1cm lebih tinggi. Dalam hal ini ,Point terdekat dan titik tidak akan membuat sudut kanan dengan garis asli. Apakah algoritma ini berfungsi dalam kasus itu?
Jenia Ivanov
3
ST_Azimuth(h.vec)- adalah kodesemu. h.vecdan h.seggaris, jadi lebih tepatnya itu harus sepertiST_Azimuth(ST_StartPoint(h.vec), ST_EndPoint(h.vec))
dmitry.v.kiselev
2
solusi di atas tampaknya tidak berfungsi dalam kasus di mana garis timur-barat memiliki bantalan tepat 90 derajat karena suatu alasan.
user7543032