Saya sedang mencari algoritma untuk mendeteksi jika dua persegi panjang berpotongan (satu pada sudut yang sewenang-wenang, yang lainnya hanya dengan garis vertikal / horizontal).
Menguji apakah sudut salah satunya ada di ALMOST yang lain berfungsi. Gagal jika persegi panjang membentuk bentuk seperti salib.
Sepertinya ide yang bagus untuk menghindari penggunaan kemiringan garis, yang akan membutuhkan kasus khusus untuk garis vertikal.
Jawaban:
Metode standar akan melakukan tes sumbu pemisah (lakukan pencarian google pada itu).
Pendeknya:
Yang menyenangkan adalah bahwa itu cukup untuk memeriksa semua tepi dari dua persegi panjang. Jika persegi panjang tidak tumpang tindih salah satu ujungnya akan menjadi sumbu pemisah.
Dalam 2D Anda dapat melakukan ini tanpa menggunakan lereng. Tepi secara sederhana didefinisikan sebagai perbedaan antara dua simpul, misalnya
Anda bisa mendapatkan garis tegak lurus dengan memutar 90 °. Dalam 2D ini semudah:
Jadi tidak ada trigonometri atau lereng yang terlibat. Normalisasi vektor ke satuan panjang juga tidak diperlukan.
Jika Anda ingin menguji apakah suatu titik ada di satu atau sisi lain dari garis tersebut, Anda bisa menggunakan produk titik. tanda akan memberi tahu Anda di sisi mana Anda berada:
Sekarang uji semua titik persegi panjang A terhadap tepi persegi panjang B dan sebaliknya. Jika Anda menemukan tepi pemisah, objek tidak bersinggungan (memberikan semua titik lain dalam B berada di sisi lain tepi yang sedang diuji - lihat gambar di bawah). Jika Anda tidak menemukan tepi pemisah, baik persegi panjang berpotongan atau satu persegi panjang terkandung di dalamnya.
Tes bekerja dengan poligon cembung apa pun ..
Amandemen: Untuk mengidentifikasi tepi yang terpisah, tidak cukup untuk menguji semua titik dari satu persegi panjang terhadap masing-masing tepi yang lain. Tepi kandidat E (di bawah) akan diidentifikasi sebagai tepi pemisah, karena semua titik dalam A berada di setengah bidang yang sama dari E. Namun, itu bukan tepi pemisah karena simpul Vb1 dan Vb2 dari B juga di setengah pesawat itu. Itu hanya akan menjadi ujung pisah jika itu tidak terjadi http://www.iassess.com/collision.png
sumber
Pada dasarnya lihat gambar berikut:
Jika kedua kotak bertabrakan, garis A dan B akan tumpang tindih.
Perhatikan bahwa ini harus dilakukan pada kedua sumbu X dan Y, dan keduanya perlu tumpang tindih untuk persegi panjang bertabrakan.
Ada artikel bagus di gamasutra.com yang menjawab pertanyaan (gambarnya dari artikel). Saya melakukan algoritma yang sama 5 tahun yang lalu dan saya harus menemukan cuplikan kode saya untuk mempostingnya di sini nanti
Amandemen : Teorema Sumbu Pemisah menyatakan bahwa dua bentuk cembung tidak tumpang tindih jika ada sumbu pemisah (yaitu satu di mana proyeksi seperti yang ditunjukkan tidak tumpang tindih). Jadi "Ada sumbu pemisah" => "Tidak ada tumpang tindih". Ini bukan implikasi ganda sehingga Anda tidak bisa menyimpulkan yang sebaliknya.
sumber
Jawaban m_pGladiator benar dan saya lebih suka. Tes sumbu terpisah adalah metode paling sederhana dan standar untuk mendeteksi tumpang tindih persegi panjang. Garis yang interval proyeksinya tidak tumpang tindih, kami sebut sumbu pemisah . Solusi Nils Pipenbrinck terlalu umum. Ini menggunakan produk titik untuk memeriksa apakah satu bentuk benar-benar di satu sisi tepi yang lain. Solusi ini sebenarnya bisa menyebabkan n-edge cembung poligon. Namun, tidak di optmized untuk dua persegi panjang.
titik kritis dari jawaban m_pGladiator adalah bahwa kita harus memeriksa proyeksi dua persegi panjang pada kedua sumbu (x dan y). Jika dua proyeksi tumpang tindih, maka kita bisa mengatakan dua persegi panjang ini tumpang tindih. Jadi komentar di atas untuk jawaban m_pGladiator salah.
untuk situasi sederhana, jika dua persegi panjang tidak diputar, kami menyajikan sebuah persegi panjang dengan struktur:
kita beri nama rectangle A, B dengan rectA, rectB.
jika salah satu dari dua persegi panjang diputar, mungkin perlu beberapa upaya untuk menentukan proyeksi mereka pada sumbu x dan y. Tetapkan struct RotatedRect sebagai berikut:
perbedaannya adalah bagaimana lebar 'sekarang sedikit berbeda: widthA' untuk rectA:
Math.sqrt(rectA.width*rectA.width + rectA.height*rectA.height) * Math.cos(rectA.angle)
widthB 'untuk rectB:Math.sqrt(rectB.width*rectB.width + rectB.height*rectB.height) * Math.cos(rectB.angle)
Dapat merujuk ke PPT GDC (Game Development Conference 2007) www.realtimecollisiondetection.net/pubs/GDC07_Ericson_Physics_Tutorial_SAT.ppt
sumber
Di Cocoa, Anda dapat dengan mudah mendeteksi apakah rectangular terpilih dipilih memotong frame NSView Anda diputar. Anda bahkan tidak perlu menghitung poligon, normal seperti itu. Cukup tambahkan metode ini ke subclass NSView Anda. Misalnya, pengguna memilih area pada superview NSView, lalu Anda memanggil metode DoesThisRectSelectMe dengan meneruskan rectArea terpilih. API convertRect: akan melakukan pekerjaan itu. Trik yang sama berfungsi ketika Anda mengklik NSView untuk memilihnya. Dalam hal ini cukup timpa metode hitTest seperti di bawah ini. API convertPoint: akan melakukan pekerjaan itu ;-)
sumber
Periksa untuk melihat apakah salah satu garis dari satu persegi panjang memotong salah satu garis dari yang lain. Persimpangan segmen garis naif mudah untuk kode.
Jika Anda membutuhkan kecepatan lebih, ada algoritme canggih untuk persimpangan segmen garis (garis-sapu). Lihat http://en.wikipedia.org/wiki/Line_segment_intersection
sumber
Salah satu solusinya adalah menggunakan sesuatu yang disebut No Fit Polygon. Poligon ini dihitung dari dua poligon (secara konseptual dengan menggeser satu di sekitar yang lain) dan menentukan area yang tumpang tindih poligon dengan offset relatifnya. Setelah Anda memiliki NFP ini maka Anda hanya perlu melakukan tes inklusi dengan titik yang diberikan oleh offset relatif dari dua poligon. Tes inklusi ini cepat dan mudah tetapi Anda harus membuat NFP terlebih dahulu.
Lakukan pencarian untuk No Fit Polygon di web dan lihat apakah Anda dapat menemukan algoritme untuk cembung poligon (itu akan JAUH lebih kompleks jika Anda memiliki poligon cekung). Jika Anda tidak dapat menemukan apa pun maka email saya di howard dot J dot dapat gmail dot com
sumber
Inilah yang saya pikir akan menangani semua kasus yang mungkin. Lakukan tes berikut.
Jika 2 tes di atas mengembalikan false maka 2 persegi panjang ini tidak tumpang tindih.
sumber
Jika Anda menggunakan Java, semua implementasi antarmuka Shape memiliki metode intersect yang mengambil persegi panjang.
sumber
Nah, metode brute force adalah berjalan di tepi persegi panjang horizontal dan memeriksa setiap titik di sepanjang tepi untuk melihat apakah jatuh di atau di persegi panjang lainnya.
Jawaban matematis adalah untuk membentuk persamaan yang menggambarkan setiap tepi dari kedua persegi panjang. Sekarang Anda dapat dengan mudah menemukan jika salah satu dari empat garis dari persegi panjang A memotong salah satu garis persegi panjang B, yang seharusnya menjadi pemecah persamaan linier sederhana (cepat).
-Adam
sumber
Anda bisa menemukan persimpangan masing-masing sisi persegi panjang bersudut dengan masing-masing sisi sumbu-sejajar. Lakukan ini dengan menemukan persamaan garis tak terbatas di mana masing-masing sisi terletak (yaitu v1 + t (v2-v1) dan v'1 + t '(v'2-v'1) pada dasarnya), menemukan titik di mana garis bertemu dengan memecahkan untuk t ketika kedua persamaan itu sama (jika mereka paralel, Anda dapat menguji untuk itu) dan kemudian menguji apakah titik itu terletak pada segmen garis antara dua simpul, yaitu apakah benar bahwa 0 <= t <= 1 dan 0 <= t '<= 1.
Namun, ini tidak mencakup kasus ketika satu persegi panjang sepenuhnya menutupi yang lain. Itu bisa Anda tutupi dengan menguji apakah keempat titik persegi panjang berada di dalam persegi panjang lainnya.
sumber
Inilah yang akan saya lakukan, untuk versi 3D dari masalah ini:
Modelkan 2 persegi panjang sebagai bidang yang dijelaskan oleh persamaan P1 dan P2, kemudian tulis P1 = P2 dan turun dari garis persamaan persimpangan, yang tidak akan ada jika bidangnya paralel (tidak ada persimpangan), atau berada di bidang yang sama, dalam hal ini Anda mendapatkan 0 = 0. Dalam hal ini Anda perlu menggunakan algoritma persimpangan persegi panjang 2D.
Lalu saya akan melihat apakah garis itu, yang ada di bidang kedua persegi panjang, melewati kedua persegi panjang. Jika ya, maka Anda memiliki persimpangan 2 persegi panjang, jika tidak Anda tidak (atau seharusnya tidak, saya mungkin telah melewatkan kotak sudut di kepalaku).
Untuk menemukan jika garis melewati persegi panjang di bidang yang sama, saya akan menemukan 2 titik persimpangan garis dan sisi-sisi persegi panjang (memodelkannya menggunakan persamaan garis), dan kemudian memastikan titik-titik persimpangan dengan di jarak.
Itulah uraian matematisnya, sayangnya saya tidak punya kode untuk melakukan hal di atas.
sumber
Cara lain untuk melakukan tes yang sedikit lebih cepat daripada menggunakan tes sumbu pemisah, adalah dengan menggunakan algoritma bilangan berkelok-kelok (hanya pada kuadran - bukan penjumlahan sudut yang sangat lambat) pada setiap simpul dari persegi panjang mana pun (dipilih secara sewenang-wenang). Jika salah satu dari simpul memiliki nomor belitan non-nol, kedua persegi panjang tumpang tindih.
Algoritme ini agak lebih panjang daripada tes sumbu pemisah, tetapi lebih cepat karena hanya membutuhkan uji setengah-pesawat jika ujung-ujungnya melintasi dua kuadran (dibandingkan dengan hingga 32 tes menggunakan metode sumbu pemisah)
Algoritma ini memiliki keunggulan lebih lanjut yang dapat digunakan untuk menguji tumpang tindih dari setiap poligon (cembung atau cekung). Sejauh yang saya tahu, algoritma hanya bekerja di ruang 2D.
sumber
Entah saya kehilangan sesuatu yang lain mengapa membuatnya begitu rumit?
jika (x1, y1) dan (X1, Y1) adalah sudut-sudut persegi panjang, maka untuk menemukan persimpangan lakukan:
sumber
Saya menerapkannya seperti ini:
Matriks mB adalah matriks transformasi affine yang mengkonversi titik dalam ruang B menjadi titik dalam ruang A. Ini termasuk rotasi dan terjemahan sederhana, rotasi plus penskalaan, dan warps affine penuh, tetapi bukan warp perspektif.
Ini mungkin tidak seoptimal mungkin. Kecepatan bukan masalah besar. Namun sepertinya itu berfungsi baik untuk saya.
sumber
Berikut ini adalah implementasi matlab dari jawaban yang diterima:
sumber
Ini adalah metode konvensional, pergi baris demi baris dan periksa apakah garis berpotongan. Ini adalah kode di MATLAB.
fungsi InterX dapat diunduh dari: https://in.mathworks.com/matlabcentral/fileexchange/22441-curve-intersections?focused=5165138&tab=function
sumber
Saya memiliki metode sederhana sendiri, jika kami memiliki 2 persegi panjang:
R1 = (min_x1, max_x1, min_y1, max_y1)
R2 = (min_x2, max_x2, min_y2, max_y2)
Mereka tumpang tindih jika dan hanya jika:
Tumpang tindih = (max_x1> min_x2) dan (max_x2> min_x1) dan (max_y1> min_y2) dan (max_y2> min_y1)
Anda dapat melakukannya untuk kotak 3D juga, sebenarnya berfungsi untuk sejumlah dimensi.
sumber
Cukup sudah dikatakan dalam jawaban lain, jadi saya hanya akan menambahkan pseudocode one-liner:
sumber