Memiliki daftar poin, bagaimana saya menemukan jika mereka berada dalam urutan searah jarum jam?
Sebagai contoh:
point[0] = (5,0)
point[1] = (6,4)
point[2] = (4,5)
point[3] = (1,5)
point[4] = (1,0)
akan mengatakan bahwa itu berlawanan arah jarum jam (atau berlawanan arah jarum jam, bagi sebagian orang).
Jawaban:
Beberapa metode yang disarankan akan gagal dalam kasus poligon non-cembung, seperti bulan sabit. Berikut ini adalah salah satu yang sederhana yang akan bekerja dengan poligon non-cembung (bahkan akan bekerja dengan poligon berpotongan sendiri seperti angka delapan, memberi tahu Anda apakah sebagian besar searah jarum jam).
Jumlahkan ujung-ujungnya, (x 2 - x 1 ) (y 2 + y 1 ). Jika hasilnya positif kurva searah jarum jam, jika negatif maka kurva berlawanan arah jarum jam. (Hasilnya adalah dua kali area tertutup, dengan konvensi +/-.)
sumber
Sum( (x[(i+1) mod N] - x[i]) * (y[i] + y[(i+1) mod N]) )
untuk i = 0 hingga N-1. Yaitu, harus mengambil indeks Modulo N (N ≡ 0
) Rumus hanya berfungsi untuk poligon tertutup . Poligon tidak memiliki tepi imajiner.Produk silang mengukur tingkat tegak lurus dua vektor. Bayangkan bahwa setiap tepi poligon Anda adalah vektor dalam bidang xy dari ruang xyz tiga dimensi (3-D). Maka produk silang dari dua sisi yang berurutan adalah vektor dalam arah-z, (arah-z positif jika segmen kedua searah jarum jam, minus arah-z jika berlawanan arah jarum jam). Besarnya vektor ini sebanding dengan sinus sudut antara dua tepi asli, sehingga mencapai maksimum ketika mereka tegak lurus, dan berangsur-angsur menghilang ketika ujung-ujungnya adalah collinear (paralel).
Jadi, untuk setiap titik (titik) poligon, hitung besarnya produk-silang dari dua sisi yang bersebelahan:
Jadi beri label pada tepinya secara berurutan seperti
edgeA
segmen daripoint0
kepoint1
danedgeB
antarapoint1
kepoint2
...
edgeE
adalah antarapoint4
danpoint0
.Kemudian Vertex A (
point0
) berada di antaraedgeE
[Daripoint4
kepoint0
]edgeA
[Daripoint0
ke `titik1 'Kedua tepi ini sendiri adalah vektor, yang koordinat x dan y dapat ditentukan dengan mengurangi koordinat titik awal dan akhir mereka:
edgeE
=point0
-point4
=(1, 0) - (5, 0)
=(-4, 0)
danedgeA
=point1
-point0
=(6, 4) - (1, 0)
=(5, 4)
danDan produk silang dari dua tepi ini berdampingan dihitung dengan menggunakan determinan dari matriks berikut, yang dibangun dengan menempatkan koordinat dua vektor di bawah simbol yang mewakili tiga sumbu koordinat (
i
,j
, &k
). Koordinat bernilai-ketiga (nol) ada karena konsep produk silang adalah konstruk 3-D, jadi kami memperluas vektor 2-D ini menjadi 3-D untuk menerapkan produk-silang:Mengingat bahwa semua produk silang menghasilkan vektor tegak lurus terhadap bidang dua vektor yang dikalikan, penentu matriks di atas hanya memiliki
k
komponen, (atau sumbu z).Rumus untuk menghitung besarnya
k
komponen sumbu z adalaha1*b2 - a2*b1 = -4* 4 - 0* 1
=-16
Besarnya nilai ini (
-16
), adalah ukuran sinus sudut antara 2 vektor asli, dikalikan dengan produk dari besarnya 2 vektor.Sebenarnya, formula lain untuk nilainya adalah
A X B (Cross Product) = |A| * |B| * sin(AB)
.Jadi, untuk kembali ke ukuran sudut yang Anda butuhkan untuk membagi nilai ini, (
-16
), dengan produk dari besarnya dua vektor.|A| * |B|
=4 * Sqrt(17)
=16.4924...
Jadi ukuran dosa (AB) =
-16 / 16.4924
=-.97014...
Ini adalah ukuran apakah segmen berikutnya setelah simpul telah membungkuk ke kiri atau ke kanan, dan seberapa banyak. Tidak perlu minum arc-sinus. Yang akan kita pedulikan hanyalah besarnya, dan tentu saja tandanya (positif atau negatif)!
Lakukan ini untuk masing-masing 4 poin lainnya di sekitar jalur tertutup, dan tambahkan nilai-nilai dari perhitungan ini di setiap titik.
Jika jumlah akhir positif, Anda bergerak searah jarum jam, negatif, berlawanan arah jarum jam.
sumber
Saya kira ini adalah pertanyaan yang cukup lama, tapi saya akan membuang solusi lain, karena itu mudah dan tidak intensif secara matematis - itu hanya menggunakan aljabar dasar. Hitung area poligon yang sudah ditandatangani. Jika negatif, poin berada dalam urutan searah jarum jam, jika positif mereka berlawanan arah jarum jam. (Ini sangat mirip dengan solusi Beta.)
Hitung area yang ditandatangani: A = 1/2 * (x 1 * y 2 - x 2 * y 1 + x 2 * y 3 - x 3 * y 2 + ... + x n * y 1 - x 1 * y n )
Atau dalam pseudo-code:
Perhatikan bahwa jika Anda hanya memeriksa pemesanan, Anda tidak perlu repot membaginya dengan 2.
Sumber: http://mathworld.wolfram.com/PolygonArea.html
sumber
previousPoint
untuk iterasi berikutnya. Sebelum memulai loop, setelpreviousPoint
ke titik terakhir larik. Trade off adalah salinan variabel lokal ekstra tetapi lebih sedikit akses array. Dan yang paling penting, tidak perlu menyentuh array input.Temukan simpul dengan y terkecil (dan x terbesar jika ada ikatan). Biarkan simpul menjadi
A
dan simpul sebelumnya dalam daftar menjadiB
dan simpul berikutnya dalam daftar menjadiC
. Sekarang hitung tanda produk silang dariAB
danAC
.Referensi:
Bagaimana cara menemukan orientasi poligon sederhana? dalam Pertanyaan yang Sering Diajukan: comp.graphics.algorithms .
Orientasi kurva di Wikipedia.
sumber
O(1)
solusi. Semua jawaban lain menghasilkanO(n)
solusi untukn
jumlah poin poligon. Untuk optimisasi yang lebih dalam, lihat sub Pertimbangan Praktis dari artikel orientasi Kurva Wikipedia yang fantastis .O(1)
hanya jika salah satu (A) poligon ini adalah cembung (dalam hal mana setiap vertex sewenang-wenang berada di cembung cembung dan karenanya cukup) atau (B) Anda sudah tahu titik dengan koordinat Y terkecil. Jika ini bukan masalahnya (yaitu, poligon ini non-cembung dan Anda tidak tahu apa-apa tentang itu),O(n)
pencarian diperlukan. Karena tidak ada penjumlahan yang diperlukan, bagaimanapun, ini masih jauh lebih cepat daripada solusi lain untuk poligon sederhana.Berikut ini adalah implementasi algoritma C # sederhana berdasarkan jawaban ini .
Mari kita asumsikan bahwa kita memiliki
Vector
tipeX
danY
properti tipedouble
.%
adalah modulo atau operator sisa yang melakukan operasi modulo yang ( menurut Wikipedia ) menemukan sisanya setelah pembagian satu angka dengan yang lain.sumber
Mulai dari salah satu simpul, dan hitung sudut yang digantikan oleh setiap sisi.
Yang pertama dan yang terakhir akan menjadi nol (jadi lewati itu); untuk selebihnya, sinus sudut akan diberikan oleh produk silang dari normalisasi ke satuan panjang (titik [n]-titik [0]) dan (titik [n-1]-titik [0]).
Jika jumlah nilai-nilai itu positif, maka poligon Anda digambar dalam arti anti-searah jarum jam.
sumber
Untuk apa nilainya, saya menggunakan mixin ini untuk menghitung urutan berliku untuk aplikasi Google Maps API v3.
Kode memanfaatkan efek samping dari area poligon: urutan simpul berliku searah jarum jam menghasilkan area positif, sedangkan urutan berliku berlawanan arah jarum jam dari titik yang sama menghasilkan area yang sama dengan nilai negatif. Kode juga menggunakan semacam API pribadi di perpustakaan geometri Google Maps. Saya merasa nyaman menggunakannya - gunakan dengan risiko Anda sendiri.
Penggunaan sampel:
Contoh lengkap dengan unit test @ http://jsfiddle.net/stevejansen/bq2ec/
sumber
Implementasi jawaban Sean dalam JavaScript:
Cukup yakin ini benar. Tampaknya berfungsi :-)
Poligon tersebut terlihat seperti ini, jika Anda bertanya-tanya:
sumber
Ini adalah fungsi yang diimplementasikan untuk OpenLayers 2 . Kondisi untuk memiliki poligon searah jarum jam adalah
area < 0
, itu dikonfirmasi oleh referensi ini .sumber
Jika Anda menggunakan Matlab, fungsi
ispolycw
mengembalikan true jika simpul poligon berada dalam urutan searah jarum jam.sumber
Sebagaimana juga dijelaskan dalam artikel Wikipedia ini , orientasi Kurva , diberikan 3 poin
p
,q
danr
di pesawat (yaitu dengan koordinat x dan y), Anda dapat menghitung tanda dari penentu berikutJika penentu negatif (yaitu
Orient(p, q, r) < 0
), maka poligon berorientasi searah jarum jam (CW). Jika penentu positif (yaituOrient(p, q, r) > 0
), poligon berorientasi berlawanan arah jarum jam (CCW). Determinan adalah nol (yaituOrient(p, q, r) == 0
) jika poinp
,q
danr
yang collinear .Dalam rumus di atas, kami menambahkan yang di depan koordinat
p
,q
danr
karena kami menggunakan koordinat homogen .sumber
Saya pikir agar beberapa poin diberikan searah jarum jam, semua sisi harus positif, bukan hanya jumlah sisi. Jika satu sisi negatif dari setidaknya 3 poin diberikan berlawanan arah jarum jam.
sumber
Solusi C # / LINQ saya didasarkan pada saran lintas produk dari @charlesbretana di bawah ini. Anda dapat menentukan referensi normal untuk belitan. Ini harus bekerja selama kurva sebagian besar di bidang didefinisikan oleh vektor atas.
dengan tes unit
sumber
Ini solusi saya menggunakan penjelasan di jawaban lain:
sumber
Metode yang jauh lebih sederhana secara komputasi, jika Anda sudah tahu titik di dalam poligon :
Pilih segmen garis mana saja dari poligon asli, titik, dan koordinatnya dalam urutan itu.
Tambahkan titik "di dalam" yang diketahui, dan bentuk segitiga.
Hitung CW atau CCW seperti yang disarankan di sini dengan tiga poin itu.
sumber
Setelah menguji beberapa implementasi yang tidak dapat diandalkan, algoritma yang memberikan hasil memuaskan mengenai orientasi CW / CCW di luar kotak adalah yang diposkan oleh OP di utas ini (
shoelace_formula_3
).Seperti biasa, angka positif mewakili orientasi CW, sedangkan angka negatif CCW.
sumber
Inilah solusi cepat 3.0 berdasarkan jawaban di atas:
sumber
Solusi lain untuk ini;
Ambil semua simpul sebagai array seperti ini;
sumber
Solusi untuk R untuk menentukan arah dan membalikkan jika searah jarum jam (merasa perlu untuk objek owin):
sumber
Walaupun jawaban ini benar, secara matematis mereka lebih kuat daripada yang diperlukan. Asumsikan koordinat peta, di mana titik paling utara adalah titik tertinggi di peta. Temukan titik paling utara, dan jika 2 titik mengikat, itu adalah yang paling utara lalu paling timur (ini adalah titik yang digunakan lhf dalam jawabannya). Dalam poin Anda,
titik [0] = (5,0)
poin [1] = (6,4)
poin [2] = (4,5)
poin [3] = (1,5)
poin [4] = (1,0)
Jika kita mengasumsikan bahwa P2 adalah yang paling utara maka titik timur baik titik sebelumnya atau berikutnya menentukan searah jarum jam, CW, atau CCW. Karena titik paling utara adalah di wajah utara, jika P1 (sebelumnya) ke P2 bergerak ke timur arahnya adalah CW. Dalam hal ini, ia bergerak ke barat, jadi arahnya adalah CCW sebagaimana jawaban yang diterima mengatakan. Jika titik sebelumnya tidak memiliki gerakan horizontal, maka sistem yang sama berlaku untuk titik berikutnya, P3. Jika P3 berada di sebelah barat P2, berarti, maka pergerakannya adalah CCW. Jika gerakan P2 ke P3 adalah timur, di barat dalam hal ini, gerakannya adalah CW. Asumsikan bahwa nte, P2 dalam data Anda, adalah titik paling utara kemudian timur dan prv adalah titik sebelumnya, P1 dalam data Anda, dan nxt adalah titik berikutnya, P3 dalam data Anda, dan [0] horizontal atau timur / barat di mana barat kurang dari timur, dan [1] vertikal.
sumber
.x
dan.y
menggunakan struct, daripada[0]
dan[1]
. Saya tidak tahu apa kata kode Anda, pertama kali saya meliriknya.)Kode C # untuk mengimplementasikan jawaban lhf :
sumber
Berikut ini implementasi Python 3 sederhana berdasarkan jawaban ini (yang, pada gilirannya, didasarkan pada solusi yang diusulkan dalam jawaban yang diterima )
sumber
temukan pusat massa titik-titik ini.
misalkan ada garis dari titik ini ke poin Anda.
temukan sudut antara dua garis untuk line0 line1
daripada melakukannya untuk line1 dan line2
...
...
jika sudut ini meningkat secara monoton daripada berlawanan,
lain jika menurun secara monoton searah jarum jam
lain (tidak monoton)
Anda tidak bisa memutuskan, jadi itu tidak bijaksana
sumber