Saya baru-baru ini menemukan masalah di mana saya memiliki empat lingkaran (titik tengah dan radius) dan harus menghitung luas persatuan lingkaran-lingkaran ini.
Contoh gambar:
Untuk dua lingkaran itu cukup mudah,
Saya hanya bisa menghitung pecahan dari setiap area lingkaran yang tidak ada di dalam segitiga dan kemudian menghitung luas segitiga.
Tetapi apakah ada algoritma pintar yang dapat saya gunakan jika ada lebih dari dua lingkaran?
Jawaban:
Temukan semua persimpangan lingkaran pada keliling luar (misalnya B, D, F, H pada diagram berikut). Hubungkan mereka bersama-sama dengan pusat lingkaran yang sesuai untuk membentuk poligon. Luas gabungan lingkaran adalah luas poligon + luas irisan lingkaran yang ditentukan oleh titik potong berurutan dan pusat lingkaran di antara keduanya. Anda juga harus memperhitungkan lubang apa pun.
sumber
Saya yakin ada algoritme yang cerdas, tetapi berikut adalah algoritme yang bodoh untuk disimpan karena harus mencarinya;
Tentu itu bodoh, tapi:
sumber
Jawaban Semut Aasma memberikan ide dasar, tetapi saya ingin membuatnya sedikit lebih konkret. Perhatikan lima lingkaran di bawah ini dan cara penguraiannya.
Mengidentifikasi 3 jenis titik ini mudah. Sekarang buat struktur data grafik di mana titik-titiknya adalah titik-titik biru dan titik-titik merah dengan interior putih. Untuk setiap lingkaran, taruh tepi antara tengah lingkaran (titik biru) dan setiap perpotongannya (titik merah dengan interior putih) pada batasnya.
Ini menguraikan gabungan lingkaran menjadi satu set poligon (berbayang biru) dan potongan pai melingkar (berbayang hijau) yang terputus-putus berpasangan dan menutupi penyatuan asli (yaitu, partisi). Karena setiap bagian di sini adalah sesuatu yang mudah untuk menghitung luasnya, Anda dapat menghitung luas gabungan dengan menjumlahkan luas bagian.
sumber
Untuk solusi yang berbeda dari solusi sebelumnya, Anda dapat menghasilkan estimasi dengan presisi arbitrer menggunakan quadtree.
Ini juga berlaku untuk semua penyatuan bentuk jika Anda dapat mengetahui apakah ada persegi di dalam atau di luar atau memotong bentuk.
Setiap sel memiliki salah satu status: kosong, penuh, parsial
Algoritme terdiri dari "menggambar" lingkaran di quadtree yang dimulai dengan resolusi rendah (misalnya, 4 sel ditandai sebagai kosong). Setiap sel adalah:
Setelah selesai, Anda dapat menghitung estimasi area: sel penuh memberikan batas bawah, sel kosong memberikan batas yang lebih tinggi, sel parsial memberikan kesalahan area maks.
Jika kesalahan terlalu besar untuk Anda, perbaiki sel parsial sampai Anda mendapatkan presisi yang tepat.
Saya pikir ini akan lebih mudah diimplementasikan daripada metode geometris yang mungkin memerlukan banyak kasus khusus.
sumber
Saya suka pendekatan pada kasus 2 lingkaran yang berpotongan - inilah cara saya menggunakan sedikit variasi dari pendekatan yang sama untuk contoh yang lebih kompleks.
Ini mungkin memberikan wawasan yang lebih baik dalam menggeneralisasi algoritme untuk sejumlah besar lingkaran semi-tumpang tindih.
Perbedaannya di sini adalah saya mulai dengan menghubungkan pusat (jadi ada simpul antara pusat lingkaran, bukan di antara tempat-tempat di mana lingkaran berpotongan) Saya pikir ini memungkinkannya menggeneralisasi dengan lebih baik.
(dalam praktiknya, mungkin metode monte-carlo bermanfaat)
(sumber: secretGeek.net )
sumber
Jika Anda menginginkan jawaban yang terpisah (bukan jawaban berkelanjutan), Anda dapat melakukan sesuatu yang mirip dengan algoritma lukisan piksel.
Gambar lingkaran pada kisi, lalu warnai setiap sel kisi jika sebagian besar berada di dalam lingkaran (yaitu, setidaknya 50% areanya ada di dalam salah satu lingkaran). Lakukan ini untuk seluruh kisi (di mana kisi mencakup semua area yang dicakup oleh lingkaran), lalu hitung jumlah sel berwarna di kisi.
sumber
Hmm, masalah yang sangat menarik. Pendekatan saya mungkin akan menjadi sesuatu di sepanjang garis berikut:
(ini berlaku untuk semua bentuk, baik itu lingkaran atau lainnya)
Di mana
A ∪ B
berarti A serikat B danA ∩ B
berarti A berpotongan B (Anda bisa menyelesaikannya dari langkah pertama.(Ini sama seperti di atas yang
A
telah diganti denganA∪B
)Di mana
area(A∪B)
kami baru saja berolahraga, danarea((A∪B)∩C)
dapat ditemukan:Dimana lagi Anda dapat menemukan area (A∩B∩C) dari atas.
Sedikit rumit adalah langkah terakhir - semakin banyak lingkaran yang ditambahkan, semakin kompleks jadinya. Saya percaya ada perluasan untuk mengerjakan area persimpangan dengan persatuan terbatas, atau sebagai alternatif Anda mungkin dapat mengerjakannya secara rekursif.
Juga berkenaan dengan penggunaan Monte-Carlo untuk memperkirakan luas itersection, saya percaya mungkin untuk mengurangi persimpangan sejumlah lingkaran acak ke persimpangan 4 lingkaran itu, yang dapat dihitung dengan tepat (tidak tahu bagaimana melakukan ini namun).
Mungkin ada cara yang lebih baik untuk melakukan ini btw - kompleksitas meningkat secara signifikan (mungkin secara eksponensial, tapi saya tidak yakin) untuk setiap lingkaran tambahan yang ditambahkan.
sumber
Saya telah mengerjakan masalah simulasi bidang bintang yang tumpang tindih, mencoba memperkirakan jumlah bintang sebenarnya dari area cakram aktual di bidang padat, di mana bintang terang yang lebih besar dapat menutupi bintang yang lebih redup. Saya juga berharap dapat melakukan ini dengan analisis formal yang ketat, tetapi tidak dapat menemukan algoritme untuk tugas tersebut. Saya menyelesaikannya dengan menghasilkan bidang bintang pada latar belakang biru sebagai cakram hijau, yang diameternya ditentukan oleh algoritme probabilitas. Rutinitas sederhana dapat memasangkannya untuk melihat apakah ada tumpang tindih (mengubah pasangan bintang menjadi kuning); kemudian hitungan piksel warna menghasilkan area yang diamati untuk dibandingkan dengan area teoritis. Ini kemudian menghasilkan kurva probabilitas untuk hitungan sebenarnya. Brute force mungkin, tapi sepertinya berhasil. (sumber: 2from.com )
sumber
Berikut adalah algoritme yang seharusnya mudah diterapkan dalam praktiknya, dan dapat disesuaikan untuk menghasilkan kesalahan kecil yang sewenang-wenang:
Langkah 2 dan 3 dapat dilakukan dengan menggunakan algoritme standar yang mudah ditemukan dari geometri komputasi.
Jelas, semakin banyak sisi yang Anda gunakan untuk setiap poligon yang mendekati, semakin mendekati jawaban Anda yang tepat. Anda bisa memperkirakan menggunakan poligon bertuliskan dan berbatas untuk mendapatkan batasan pada jawaban yang tepat.
sumber
Ada solusi efisien untuk masalah ini menggunakan apa yang dikenal sebagai diagram daya. Ini adalah matematika yang sangat berat dan bukan sesuatu yang ingin saya tangani begitu saja. Untuk solusi yang "mudah", cari algoritme sapuan baris. Prinsip dasarnya di sini adalah Anda membagi gambar menjadi beberapa strip, di mana menghitung luas di setiap strip relatif mudah.
Jadi, pada gambar yang berisi semua lingkaran tanpa ada yang tergesek, gambar garis horizontal pada setiap posisi yang merupakan puncak lingkaran, bagian bawah lingkaran, atau perpotongan 2 lingkaran. Perhatikan bahwa di dalam strip ini, semua area yang perlu Anda hitung terlihat sama: sebuah "trapezium" dengan dua sisi diganti dengan segmen lingkaran. Jadi, jika Anda dapat mengetahui cara menghitung bentuk seperti itu, Anda cukup melakukannya untuk semua bentuk individu dan menjumlahkannya. Kompleksitas pendekatan naif ini adalah O (N ^ 3), di mana N adalah jumlah lingkaran pada gambar. Dengan beberapa penggunaan struktur data yang cerdas, Anda dapat meningkatkan metode sapuan garis ini ke O (N ^ 2 * log (N)), tetapi kecuali Anda benar-benar membutuhkannya, itu mungkin tidak sepadan dengan masalahnya.
sumber
Saya menemukan tautan ini yang semoga bermanfaat. Namun tampaknya tidak ada jawaban yang pasti. Jawaban Google . Referensi lain untuk tiga lingkaran adalah teorema Haruki . Ada kertas di sana juga.
sumber
Bergantung pada masalah apa yang Anda coba selesaikan, mungkin cukup untuk mendapatkan batas atas dan bawah. Batas atasnya mudah, hanya jumlah dari semua lingkaran. Untuk batas bawah, Anda dapat memilih satu jari-jari sehingga tidak ada lingkaran yang tumpang tindih. Untuk lebih baik menemukan radius terbesar (hingga radius sebenarnya) untuk setiap lingkaran agar tidak tumpang tindih. Ini juga harus cukup sepele untuk menghapus semua lingkaran yang sepenuhnya tumpang tindih (Semua lingkaran memenuhi | P_a - P_b | <= r_a) di mana P_a adalah pusat lingkaran A, P_b adalah pusat lingkaran B, dan r_a adalah jari-jari A ) dan ini lebih baik dari batas atas dan bawah. Anda juga bisa mendapatkan Batas atas yang lebih baik jika Anda menggunakan rumus pasangan pada pasangan sembarang, bukan hanya jumlah semua lingkaran. Mungkin ada cara yang baik untuk memilih yang "terbaik"
Mengingat batas atas dan bawah, Anda mungkin dapat menyesuaikan pendekatan Monte-carlo dengan lebih baik, tetapi tidak ada hal spesifik yang terlintas dalam pikiran. Pilihan lain (sekali lagi tergantung pada aplikasi Anda) adalah meraster lingkaran dan menghitung piksel. Ini pada dasarnya adalah pendekatan Monte-carlo dengan distribusi tetap.
sumber
Ini dapat diselesaikan menggunakan Teorema Green , dengan kompleksitas n ^ 2log (n). Jika Anda belum familiar dengan Teorema Green dan ingin tahu lebih banyak, berikut adalah video dan catatan dari Khan Academy. Tapi demi masalah kita, saya pikir deskripsi saya sudah cukup.
Persamaan Umum Teorema Green
Jika saya menempatkan L dan M seperti itu
Kondisi
maka RHS hanyalah luas dari Wilayah R dan dapat diperoleh dengan menyelesaikan integral tertutup atau LHS dan inilah yang akan kita lakukan.
Semua serikat pekerja dapat dipecah menjadi kumpulan lingkaran yang saling berpotongan
Jadi Mengintegrasikan sepanjang jalur berlawanan arah jarum jam memberi kita Area dari wilayah tersebut dan mengintegrasikan sepanjang searah jarum jam memberi kita negatif Area . Begitu
AreaOfUnion = (Integrasi sepanjang busur merah berlawanan arah jarum jam + Integrasi sepanjang busur biru searah jarum jam)
Tetapi trik kerennya adalah jika untuk setiap lingkaran jika kita mengintegrasikan busur yang tidak ada di dalam lingkaran lain, kita mendapatkan area yang diperlukan yaitu kita mendapatkan integrasi dalam arah berlawanan arah jarum jam di sepanjang semua busur merah dan integrasi di sepanjang semua busur biru di sepanjang arah jarum jam. PEKERJAAN SELESAI!!!
Ini adalah tautan GitHub ke Kode C ++ saya
sumber
Pendekatan lukisan-piksel (seperti yang disarankan oleh @Loadmaster) lebih unggul daripada solusi matematika dalam berbagai cara:
Satu-satunya kelemahan lukisan piksel adalah akurasi solusi yang terbatas. Tapi itu bisa disesuaikan dengan hanya menampilkan kanvas yang lebih besar atau lebih kecil sesuai tuntutan situasi. Perhatikan juga, bahwa anti-aliasing dalam kode rendering 2D (sering diaktifkan secara default) akan menghasilkan akurasi yang lebih baik dari tingkat piksel. Jadi, misalnya, merender gambar 100x100 ke dalam kanvas dengan dimensi yang sama seharusnya, menurut saya, menghasilkan akurasi pada urutan 1 / (100 x 100 x 255) = 0,000039% ... yang mungkin "cukup baik" untuk semua kecuali masalah yang paling menuntut.
sumber