Saya memiliki garis dari A ke B dan lingkaran diposisikan di C dengan jari-jari R.
Apa algoritma yang baik untuk digunakan untuk memeriksa apakah garis memotong lingkaran? Dan pada koordinat apa di sepanjang tepi lingkaran itu terjadi?
Saya memiliki garis dari A ke B dan lingkaran diposisikan di C dengan jari-jari R.
Apa algoritma yang baik untuk digunakan untuk memeriksa apakah garis memotong lingkaran? Dan pada koordinat apa di sepanjang tepi lingkaran itu terjadi?
Jawaban:
Pengambilan
Hitung:
d = L - E (Vektor arah sinar, dari awal hingga akhir)
f = E - C (Vektor dari pusat bola ke mulai sinar)
Kemudian persimpangan ditemukan oleh ..
Memasukkan:
P = E + t * d
Ini adalah persamaan parametrik:
P x = E x + td x
P y = E y + td y
ke dalam
(x - h) 2 + (y - k) 2 = r 2
(h, k) = pusat lingkaran.
mendapatkan:
x 2 - 2xh + h 2 + y 2 - 2yk + k 2 - r 2 = 0
x = e x + td x
y = e y + td y
(e x + td x ) 2 - 2 (e x + td x ) h + h 2 + (e y + td y ) 2 - 2 (e y + td y ) k + k 2 - r 2 = 0
e x 2 + 2e x td x + t 2 d x 2 - 2e x h - 2td x h + h 2 + e y 2 + 2 y td y + t 2 d y 2 - 2e y k - 2td y k + k 2 - r 2 = 0
t 2 (d x 2 + d y 2 ) + 2t (e x d x + e y d y - d x h - d y k) + e x 2 + e y 2 - 2e x h - 2e y k + h 2 + k 2 - r 2 = 0
t 2 (_d * _d) + 2t (_e * _d - _d * _c) + _e * _e - 2 (_e * _c) + _c * _c - r 2 = 0
* Di mana _d adalah vektor d dan * adalah produk titik. *
t 2 (_d * _d) + 2t (_d * (_e - _c)) + (_e - _c) * (_e - _c) - r 2 = 0
t 2 (_d * _d) + 2t (_d * _f) + _f * _f - r 2 = 0
Jadi kita mendapatkan:
t 2 * (d DOT d) + 2t * (f DOT d) + (f DOT f - r 2 ) = 0
Jadi memecahkan persamaan kuadratik:
sumber
P = E + t * d
Apat
?Sepertinya tidak ada yang mempertimbangkan proyeksi, apakah saya benar-benar keluar jalur di sini?
Proyeksikan vektor
AC
keAB
. Vektor yang diproyeksikan,,AD
memberikan titik baruD
.Jika jarak antara
D
danC
lebih kecil dari (atau sama dengan),R
kami memiliki persimpangan.Seperti ini:
sumber
CD
adalah proyeksi, itu tegak lurus oleh definisi.Saya akan menggunakan algoritma untuk menghitung jarak antara titik (pusat lingkaran) dan garis (garis AB). Ini kemudian dapat digunakan untuk menentukan titik persimpangan garis dengan lingkaran.
Katakanlah kita memiliki titik A, B, C. Axe dan Ay adalah komponen x dan y dari titik A. Sama untuk B dan C. Skalar R adalah jari-jari lingkaran.
Algoritma ini mensyaratkan bahwa A, B dan C adalah titik yang berbeda dan R bukan 0.
Di sini adalah algoritma
sumber
t+dt
dant-dt
di garis.t
adalah titik pada garis yang paling dekat dengan pusat lingkaran. Titik persimpangan dengan lingkaran berada pada jarak simetris darit
. Titik persimpangan berada pada "jarak"t-dt
dant+dt
. Saya mengutip jarak karena itu bukan jarak euclidian. Untuk mendapatkan jarak euclidian dariA
tempatt=0
, Anda harus mengalikan nilainya denganLAB
.t=0
. Titik B dit=LAB
. Ketika kedua titik persimpangan (t1=t-td
dant2=t+td
) memiliki nilai negatif daripada persimpangan berada di luar bagian (di belakang titik A melihat dari sisi bagian titik). Ketika t1 dan t2 lebih besar dari LAB maka mereka berada di luar juga (kali ini di belakang titik B). Persimpangan t1 (atau t2) terjadi antara A dan B hanya ketika t1 (atau t2) itu antara 0 dan LAB.Oke, saya tidak akan memberi Anda kode, tetapi karena Anda telah menandai ini algoritma, Saya tidak berpikir itu penting bagi Anda. Pertama, Anda harus mendapatkan vektor tegak lurus terhadap garis.
Anda akan memiliki variabel yang tidak dikenal di
y = ax + c
(c
tidak akan diketahui )Untuk menyelesaikannya, Hitung nilainya ketika garis melewati pusat lingkaran.
Yaitu,
Pasang di lokasi pusat lingkaran ke persamaan garis dan pecahkan untuk
c
.Kemudian hitung titik persimpangan dari garis asli dan normalnya.
Ini akan memberi Anda titik terdekat pada garis ke lingkaran.
Hitung jarak antara titik ini dan pusat lingkaran (menggunakan besarnya vektor).
Jika ini kurang dari jari-jari lingkaran - voila, kita memiliki persimpangan!
sumber
Metode lain menggunakan rumus luas segitiga ABC. Tes persimpangan lebih sederhana dan lebih efisien daripada metode proyeksi, tetapi menemukan koordinat titik persimpangan membutuhkan lebih banyak pekerjaan. Setidaknya itu akan ditunda ke titik yang diperlukan.
Rumus untuk menghitung luas segitiga adalah: area = bh / 2
di mana b adalah panjang dasar dan h adalah tinggi. Kami memilih segmen AB untuk menjadi basis sehingga h adalah jarak terpendek dari C, pusat lingkaran, ke garis.
Karena area segitiga juga dapat dihitung dengan produk titik vektor kita dapat menentukan h.
PEMBARUAN 1:
Anda bisa mengoptimalkan kode dengan menggunakan perhitungan root kuadrat terbalik cepat yang dijelaskan di sini untuk mendapatkan perkiraan 1 / LAB yang bagus.
Menghitung titik persimpangan tidak terlalu sulit. Ini dia
Jika h = R maka garis AB bersinggungan dengan lingkaran dan nilai dt = 0 dan E = F. Koordinat titik adalah dari E dan F.
Anda harus memeriksa bahwa A berbeda dari B dan panjang segmen tidak nol jika ini dapat terjadi dalam aplikasi Anda.
sumber
Saya menulis skrip kecil untuk menguji persimpangan dengan memproyeksikan titik pusat lingkaran ke garis.
http://jsfiddle.net/ercang/ornh3594/1/
Jika Anda perlu memeriksa tabrakan dengan segmen, Anda juga perlu mempertimbangkan jarak pusat lingkaran untuk memulai dan mengakhiri poin.
https://jsfiddle.net/ercang/menp0991/
sumber
Solusi yang saya temukan ini tampak sedikit lebih mudah untuk diikuti daripada beberapa yang lain.
Pengambilan:
Saya akan memecahkan persamaan garis dalam bentuk slope-intercept. Namun, saya tidak ingin harus berurusan dengan persamaan sulit
c
sebagai titik, jadi saya hanya menggeser sistem koordinat sehingga lingkaran berada pada0,0
Ngomong-ngomong, setiap kali saya mengurangi poin dari satu sama lain, saya mengurangi poin
x
dan kemudian mengurangi poiny
, dan menempatkannya ke poin baru, kalau-kalau ada yang tidak tahu.Bagaimanapun, saya sekarang memecahkan persamaan garis dengan
p3
danp4
:Baik. Sekarang saya perlu mengatur persamaan ini sama. Pertama, saya perlu memecahkan persamaan lingkaran untuk
x
Lalu saya mengatur mereka sama:
Dan memecahkan persamaan kuadrat (
0 = ax^2 + bx + c
):Sekarang aku punya saya
a
,b
danc
.Jadi saya memasukkan ini ke dalam rumus kuadratik:
Dan gantikan dengan nilai-nilai kemudian sederhanakan sebanyak mungkin:
Ini hampir sejauh yang disederhanakan. Akhirnya, pisahkan persamaan dengan ±:
Kemudian cukup tancapkan hasil dari kedua persamaan tersebut ke
x
dalammx + b
. Untuk lebih jelasnya, saya menulis beberapa kode JavaScript untuk menunjukkan cara menggunakan ini:Saya harap ini membantu!
PS Jika ada yang menemukan kesalahan atau punya saran, silakan komentar. Saya sangat baru dan menyambut semua bantuan / saran.
sumber
underRadical
tambahan ')'Anda dapat menemukan titik pada garis tak terbatas yang terdekat dengan pusat lingkaran dengan memproyeksikan vektor AC ke vektor AB. Hitung jarak antara titik dan pusat lingkaran itu. Jika lebih besar dari R, tidak ada persimpangan. Jika jaraknya sama dengan R, garis adalah garis singgung lingkaran dan titik terdekat dengan pusat lingkaran sebenarnya adalah titik persimpangan. Jika jarak kurang dari R, maka ada 2 titik persimpangan. Mereka berbaring pada jarak yang sama dari titik terdekat ke pusat lingkaran. Jarak itu dapat dengan mudah dihitung menggunakan teorema Pythagoras. Berikut algoritma dalam pseudocode:
EDIT: kode yang ditambahkan untuk memeriksa apakah titik persimpangan yang ditemukan sebenarnya berada dalam segmen garis.
sumber
Anehnya saya bisa menjawab tetapi tidak berkomentar ... Saya menyukai pendekatan Multitaskpro dalam mengubah segalanya untuk membuat pusat lingkaran jatuh pada asalnya. Sayangnya ada dua masalah dalam kodenya. Pertama di bagian root di bawah Anda perlu menghapus kekuatan ganda. Jadi tidak:
var underRadical = Math.pow((Math.pow(r,2)*(Math.pow(m,2)+1)),2)-Math.pow(b,2));
tapi:
var underRadical = Math.pow(r,2)*(Math.pow(m,2)+1)) - Math.pow(b,2);
Dalam koordinat terakhir dia lupa untuk menggeser solusi kembali. Jadi tidak:
var i1 = {x:t1,y:m*t1+b}
tapi:
var i1 = {x:t1+c.x, y:m*t1+b+c.y};
Seluruh fungsi kemudian menjadi:
sumber
Anda perlu matematika di sini:
Misalkan A = (Xa, Ya), B = (Xb, Yb) dan C = (Xc, Yc). Setiap titik pada garis dari A ke B memiliki koordinat (alpha * Xa + (1-alpha) Xb, alpha Ya + (1-alpha) * Yb) = P
Jika titik P memiliki jarak R ke C, itu harus di lingkaran. Yang Anda inginkan adalah menyelesaikannya
itu adalah
jika Anda menerapkan rumus-ABC untuk persamaan ini untuk menyelesaikannya untuk alpha, dan menghitung koordinat P menggunakan solusi (s) untuk alpha, Anda mendapatkan titik persimpangan, jika ada.
sumber
Jika Anda menemukan jarak antara pusat bola (karena itu 3D saya anggap Anda maksud bola dan bukan lingkaran) dan garis, lalu periksa apakah jarak itu kurang dari jari-jari yang akan melakukan trik.
Titik tumbukan jelas merupakan titik terdekat antara garis dan bola (yang akan dihitung saat Anda menghitung jarak antara bola dan garis)
Jarak antara titik dan garis:
http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
sumber
Berikut ini adalah implementasi dalam Javascript. Pendekatan saya adalah pertama-tama mengubah segmen garis menjadi garis yang tak terbatas kemudian menemukan titik persimpangan. Dari sana saya memeriksa apakah titik yang ditemukan berada di segmen garis. Kode ini didokumentasikan dengan baik, Anda harus dapat mengikuti.
Anda dapat mencoba kode di sini di demo langsung ini . Kode diambil dari repo algoritme saya .
sumber
Dalam tumbukan garis lingkaran posting ini akan diperiksa dengan memeriksa jarak antara pusat lingkaran dan titik pada segmen garis (Ipoint) yang mewakili titik persimpangan antara N normal (Gambar 2) dari pusat lingkaran ke segmen garis.
( https://i.stack.imgur.com/3o6do.png )
Pada gambar 1 satu lingkaran dan satu garis ditampilkan, vektor A titik ke titik awal, vektor B titik ke titik akhir garis, vektor C titik ke pusat lingkaran. Sekarang kita harus menemukan vektor E (dari titik awal garis ke pusat lingkaran) dan vektor D (dari titik awal garis ke titik akhir garis) perhitungan ini ditunjukkan pada gambar 1.
( https://i.stack.imgur.com/7098a.png )
Pada gambar 2 kita dapat melihat bahwa vektor E diproyeksikan pada Vektor D oleh "titik produk" dari vektor E dan satuan vektor D, hasil dari produk titik adalah skalar Xp yang mewakili jarak antara titik mulai garis dan titik persimpangan (titik) dari vektor N dan vektor D. Selanjutnya vektor X ditemukan dengan mengalikan vektor satuan D dan skalar Xp.
Sekarang kita perlu menemukan vektor Z (vektor ke Ipoint), mudahnya penambahan vektor sederhana dari vektor A (titik awal on line) dan vektor X. Selanjutnya kita perlu berurusan dengan kasus-kasus khusus yang harus kita periksa adalah Ipoint pada segmen garis, jika itu bukan kita harus mencari tahu apakah itu kiri atau kanan itu, kita akan menggunakan vektor terdekat untuk menentukan titik mana yang paling dekat dengan lingkaran.
( https://i.stack.imgur.com/p9WIr.png )
Ketika proyeksi Xp negatif Ipoint berada di sebelah kiri segmen garis, vektor terdekat sama dengan vektor titik awal garis, ketika proyeksi Xp lebih besar daripada besarnya vektor D maka Ipoint kanan segmen garis kemudian vektor terdekat sama dengan vektor garis akhir titik dalam hal lain vektor terdekat sama dengan vektor Z.
Sekarang ketika kita memiliki vektor terdekat, kita perlu menemukan vektor dari pusat lingkaran ke Ipoint (vektor dist), sederhana kita hanya perlu mengurangi vektor terdekat dari vektor pusat. Selanjutnya hanya memeriksa apakah besarnya dist vektor kurang dari jari-jari lingkaran jika kemudian mereka bertabrakan, jika tidak ada tabrakan.
( https://i.stack.imgur.com/QJ63q.png )
Untuk akhirnya, kita dapat mengembalikan beberapa nilai untuk menyelesaikan tabrakan, cara termudah adalah dengan mengembalikan tumpang tindih tabrakan (kurangi jari-jari dari besaran dist vektor) dan kembali sumbu tabrakan, vektor D. Juga titik persimpangan adalah vektor Z jika diperlukan.
sumber
Jika koordinat garis adalah Ax, Ay dan Bx, By dan lingkaran pusatnya adalah Cx, Cy maka rumus garisnya adalah:
x = Kapak * t + Bx * (1 - t)
y = Ay * t + Oleh * (1 - t)
di mana 0 <= t <= 1
dan lingkaran itu
(Cx - x) ^ 2 + (Cy - y) ^ 2 = R ^ 2
jika Anda mengganti rumus x dan y dari garis ke rumus lingkaran Anda mendapatkan persamaan orde kedua dari t dan solusinya adalah titik persimpangan (jika ada). Jika Anda mendapatkan yang lebih kecil dari 0 atau lebih besar dari 1 maka itu bukan solusi tetapi itu menunjukkan bahwa garis 'menunjuk' ke arah lingkaran.
sumber
Hanya tambahan untuk utas ini ... Di bawah ini adalah versi kode yang diposting oleh pahlevan, tetapi untuk C # / XNA dan dirapikan sedikit:
sumber
Ray.Intersects(BoundingSphere)
sumber
Saya telah membuat fungsi ini untuk iOS mengikuti jawaban yang diberikan oleh
chmike
sumber
Satu lagi di c # (sebagian kelas Circle). Diuji dan bekerja seperti pesona.
Yg dibutuhkan:
sumber
Berikut ini adalah solusi yang baik dalam JavaScript (dengan semua matematika yang diperlukan dan ilustrasi langsung) https://bl.ocks.org/milkbread/11000965
Padahal
is_on
fungsi dalam solusi itu perlu modifikasi:sumber
Circle benar-benar orang jahat :) Jadi cara yang baik adalah menghindari lingkaran sejati, jika Anda bisa. Jika Anda melakukan pemeriksaan tabrakan untuk gim, Anda bisa menggunakan beberapa penyederhanaan dan hanya memiliki produk 3 titik, dan beberapa perbandingan.
Saya menyebutnya "titik lemak" atau "lingkaran tipis". jenisnya berupa elips dengan jari-jari nol searah dengan suatu segmen. tetapi jari-jari penuh dalam arah yang tegak lurus terhadap suatu ruas
Pertama, saya akan mempertimbangkan penggantian nama dan switching sistem koordinat untuk menghindari data yang berlebihan:
Kedua, indeks h dalam hvec2f berarti daripada vektor harus mendukung operasi horisontal, seperti dot () / det (). Yang berarti komponen-komponennya harus ditempatkan dalam register xmm yang terpisah, untuk menghindari pengocokan / hadd'ing / hsub'ing. Dan di sini kita mulai, dengan versi paling banyak dari pendeteksian tabrakan paling sederhana untuk game 2D:
Saya ragu Anda dapat mengoptimalkannya lebih jauh. Saya menggunakannya untuk deteksi tabrakan balap mobil yang digerakkan oleh jaringan saraf, untuk memproses jutaan langkah iterasi.
sumber
Fungsi Java ini mengembalikan Objek DVec2. Dibutuhkan DVec2 untuk pusat lingkaran, jari-jari lingkaran, dan Garis.
sumber
Ini solusi saya di TypeScript, mengikuti gagasan yang disarankan oleh @Mizipzor (menggunakan proyeksi):
sumber
Saya tahu sudah lama sejak utas ini terbuka. Dari jawaban yang diberikan oleh chmike dan ditingkatkan oleh Aqib Mumtaz. Mereka memberikan jawaban yang baik tetapi hanya bekerja untuk garis yang tak terbatas seperti kata Aqib. Jadi saya menambahkan beberapa perbandingan untuk mengetahui apakah segmen garis menyentuh lingkaran, saya menulisnya dengan Python.
sumber
Berikut adalah solusi yang ditulis dalam golang. Metode ini mirip dengan beberapa jawaban lain yang diposting di sini, tetapi tidak persis sama. Mudah diimplementasikan, dan telah diuji. Berikut langkah-langkahnya:
Nilai untuk A, B, dan C untuk kuadrat diturunkan di sini, di mana (n-et) dan (m-dt) adalah persamaan untuk koordinat garis x dan y, masing-masing. r adalah jari-jari lingkaran.
Karena itu A = ee + dd, B = - 2 (en + dm), dan C = nn + mm - rr.
Berikut adalah kode golang untuk fungsinya:
Saya mengujinya dengan fungsi ini, yang menegaskan bahwa titik solusi berada dalam segmen garis dan pada lingkaran. Itu membuat segmen tes dan menyapu di sekitar lingkaran yang diberikan:
Berikut ini adalah hasil tes:
Akhirnya, metode ini mudah diperluas ke kasus sinar mulai dari satu titik, melewati titik lain dan meluas hingga tak terbatas, dengan hanya menguji jika t> 0 atau t <1 tetapi tidak keduanya.
sumber
Saya hanya butuh itu, jadi saya datang dengan solusi ini. Bahasa ini maxscript, tetapi harus dengan mudah diterjemahkan ke bahasa lain. sideA, sideB dan CircleRadius adalah skalar, variabel sisanya adalah titik sebagai [x, y, z]. Saya mengasumsikan z = 0 untuk menyelesaikan di pesawat XY
sumber
Solusi dalam python, berdasarkan @ Jo Skeen
sumber
Anda dapat mengambil titik-titik spasi X yang merata dari garis dan jika ada di dalam lingkaran, ada tabrakan
sumber