Area gabungan dari lingkaran yang tumpang tindih


107

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?


15
Ini adalah masalah yang sangat menarik, saya ingat melihat ini di kelas geometri sekolah menengah, tetapi tidak pernah menemukan solusi. Jika Anda tidak dapat menemukan jawaban di sini, coba posting di mathoverflow.net dan biarkan ahli matematika mengetahuinya: P
Charles Ma

25
terkadang pemrogram sejati membutuhkan matematika nyata
fa.

1
Bagaimana dengan menjawab pertanyaan ini - "Kami memiliki perwakilan penjualan yang tinggal di 4 lokasi ini, yang masing-masing melayani area dengan 4 radius ini. Berapa banyak negara yang kami cakup?" Jika Anda memiliki database perwakilan penjualan yang berubah, ini menjadi pertanyaan pemrograman!
Chris Roberts

5
Sebenarnya, ini adalah jenis masalah yang sering dipikirkan oleh programmer sebenarnya.
MAK

2
@zvolkov: papan sirkuit dijelaskan dengan bahasa yang menjatuhkan kotak dan lingkaran ke bawah dan secara opsional menyeretnya. "Hitung luas tembaga". (Ini dapat diperlukan untuk menghitung waktu etsa, tahu apakah akan menambahkan karya seni pemulungan, berbagai hal.)
DigitalRoss

Jawaban:


97

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.

lingkaran tumpang tindih


17
Apa yang terjadi jika ada lubang di tengahnya?
John Gietzen

3
Anda harus mengurangi poligon yang terhubung ke tengah untuk lubang dari total dan menambahkan irisan lingkaran untuk poligon tersebut ke total.
Semut Aasma

3
bagus tapi saya rasa ini akan membutuhkan banyak detail implementasi untuk menangani semua kasus khusus (lingkaran di dalam yang lain, tidak ada persimpangan, lubang, kontak satu titik ...)
fa.

1
Kasus khusus cukup mudah. Lingkaran di dalam yang lain dibuang dengan tidak memiliki persimpangan perimeter. Kontak satu titik pada dasarnya adalah dua persimpangan dengan jarak nol. Bentuk terputus dapat ditemukan melalui algoritma komponen terhubung pada grafik dimana dua lingkaran dihubungkan jika jarak pusat kurang dari jumlah jari-jarinya. Semua lubang adalah poligon kecuali yang memiliki luas terbesar. Persimpangan perimeter adalah semua persimpangan yang tidak persis berada di dalam lingkaran mana pun.
Ants Aasma

4
ya, tetapi batas lubang juga (kecil) busur. Saya masih berpikir ini membutuhkan banyak kode agar berfungsi dengan baik.
fa.

32

Saya yakin ada algoritme yang cerdas, tetapi berikut adalah algoritme yang bodoh untuk disimpan karena harus mencarinya;

  • letakkan kotak pembatas di sekitar lingkaran;
  • menghasilkan titik-titik acak dalam kotak pembatas;
  • mencari tahu apakah titik acak ada di dalam salah satu lingkaran;
  • menghitung luas dengan beberapa penambahan dan pembagian sederhana (proporsi_dari_penunjuk_di dalam * kotak_batas_bidang).

Tentu itu bodoh, tapi:

  • Anda bisa mendapatkan jawaban seakurat yang Anda inginkan, hanya menghasilkan lebih banyak poin;
  • ini akan bekerja untuk bentuk apa pun yang dapat Anda hitung perbedaan bagian dalam / luarnya;
  • itu akan paralel dengan indah sehingga Anda dapat menggunakan semua inti Anda.

2
Ini akan berhasil, tetapi metode Monte-Carlo seperti ini, hanya berdasarkan pada pengambilan sampel yang seragam, umumnya tidak memiliki tingkat konvergensi terbaik.
ShreevatsaR

2
Maaf, meskipun saya menghargai usaha Anda dan berpikir bahwa solusi Anda "praktis dapat digunakan", saya menganggap pendekatan Anda sangat salah. Ini adalah masalah daripada yang bisa dan harus diselesaikan dengan matematika, bukan kekerasan. Membuang energi dan fokus pada masalah seperti ini adalah pemborosan dan pemborosan.
mafu

5
Anda benar, saya malu pada diri saya sendiri, tetapi saya memiliki cluster dengan 12.000 core, saya mampu untuk menjadi mewah. Dan saya tidak tahu cara membuat solusi matematika yang elegan berskala untuk banyak prosesor itu.
Kinerja Tinggi Mark

8
Tidak ada yang salah dengan pendekatan Monte-Carlo (atau acak), asalkan memberikan tingkat akurasi yang diperlukan dan melakukannya dalam waktu yang wajar.
MAK

@mafutr, Anda pasti benar. Namun, mudah untuk membuat kesalahan kecil dalam matematika. Solusi ini menyediakan cara sederhana untuk menguji kebenaran.
Richard

18

Jawaban Semut Aasma memberikan ide dasar, tetapi saya ingin membuatnya sedikit lebih konkret. Perhatikan lima lingkaran di bawah ini dan cara penguraiannya.

Contoh

  • Titik biru adalah pusat lingkaran.
  • Titik merah merupakan perpotongan batas lingkaran.
  • Titik merah dengan interior putih merupakan perpotongan batas lingkaran yang tidak terdapat pada lingkaran lain .

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.


Saya pikir saya dapat menghitung satu set titik merah / putih dengan cukup mudah namun teori grafik saya tidak terlalu bagus: secara algoritme, bagaimana Anda mendapatkan dari daftar node + tepi ke area yang dihitung?
pengguna999305

1
Algoritme dapat disederhanakan dengan menggunakan sekumpulan segitiga yang tidak tumpang tindih, bukan poligon. Busur (area hijau) adalah area yang hanya terdapat dalam satu lingkaran. Perluas ukuran poligon saat Anda menambahkan lebih banyak lingkaran. (pada akhirnya Anda bisa lupa bahwa Anda sedang membicarakan poligon). Itu membuat properti boolean dan area lebih mudah dihitung juga. Saat titik merah berongga menjadi titik merah solid, Anda cukup menambahkan lebih banyak segitiga ke set Anda, dan Anda menyesuaikan busur itu akan "dimakan" oleh lebih banyak lingkaran yang berpotongan.
Steve

16

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:

  • di dalam setidaknya satu lingkaran, lalu tandai sel sebagai penuh,
  • di luar semua lingkaran, tandai sel sebagai kosong,
  • jika tidak, tandai sel sebagai parsial.

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.


3
Dugaan saya adalah bahwa ini akan menyatu lebih cepat daripada algoritma monte carlo inside / outside point juga.
Frank Krueger

Ini tampaknya jauh lebih mudah untuk diterapkan. Jelas metode brute force terbaik yang disarankan. Terima kasih!
Anton Hansson

kekerasan di sini disebut teorema pemerasan
fa.

Itulah jenis algoritma yang Anda gunakan dalam aritmatika interval. en.wikipedia.org/wiki/Interval_arithmetic
rjmunro

13

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)

teks alt
(sumber: secretGeek.net )


1
Saya pikir melakukan jenis pembagian poligon yang disarankan oleh gambar Anda mungkin akan menjadi pendekatan yang sangat bagus. Ada banyak detail yang harus dikerjakan untuk mengkodekannya. Bagaimana itu menangani rantai dua puluh lingkaran, yang masing-masing hanya tumpang tindih dengan yang terakhir dan selanjutnya dalam rantai? Mudah diketahui dengan tangan, tetapi apa algoritme Anda?
PeterAllenWebb

4

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.


3

Hmm, masalah yang sangat menarik. Pendekatan saya mungkin akan menjadi sesuatu di sepanjang garis berikut:

  • Cari cara untuk mencari tahu luas persimpangan antara jumlah lingkaran yang berubah-ubah, yaitu jika saya memiliki 3 lingkaran, saya harus dapat menentukan perpotongan antara lingkaran-lingkaran itu. Metode "Monte-Carlo" akan menjadi cara yang baik untuk memperkirakan hal ini ( http://local.wasp.uwa.edu.au/~pbourke/geometry/circlearea/ ).
  • Singkirkan semua lingkaran yang seluruhnya terdapat dalam lingkaran lain yang lebih besar (lihat jari-jari dan modulus jarak antara pusat kedua lingkaran) Saya rasa tidak wajib.
  • Pilih 2 lingkaran (beri nama A dan B) dan hitung luas total menggunakan rumus ini:

(ini berlaku untuk semua bentuk, baik itu lingkaran atau lainnya)

area(A∪B) = area(A) + area(B) - area(A∩B)

Di mana A ∪ Bberarti A serikat B dan A ∩ Bberarti A berpotongan B (Anda bisa menyelesaikannya dari langkah pertama.

  • Sekarang terus menambahkan lingkaran dan terus mengerjakan area yang ditambahkan sebagai penjumlahan / pengurangan area lingkaran dan area perpotongan antar lingkaran. Misalnya untuk 3 lingkaran (sebut lingkaran ekstra C) kita menghitung luasnya menggunakan rumus ini:

(Ini sama seperti di atas yang Atelah diganti dengan A∪B)

area((A∪B)∪C) = area(A∪B) + area(C) - area((A∪B)∩C)

Di mana area(A∪B)kami baru saja berolahraga, dan area((A∪B)∩C)dapat ditemukan:

area((A∪B)nC) = area((A∩C)∪(B∩C)) = area(A∩C) + area(A∩B) - area((A∩C)∩(B∩C)) = area(A∩C) + area(A∩B) - area(A∩B∩C)

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.


Ada apa dengan formatnya? Juga maaf tentang penggunaan n dan u untuk persimpangan dan persatuan, mungkin ada cara yang lebih baik ...
Justin

1
menambahkan beberapa tanda unicode union (∪) dan intersection (∩). semoga berhasil.
Spoike

3

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 )


2

Berikut adalah algoritme yang seharusnya mudah diterapkan dalam praktiknya, dan dapat disesuaikan untuk menghasilkan kesalahan kecil yang sewenang-wenang:

  1. Perkirakan setiap lingkaran dengan poligon beraturan yang berpusat pada titik yang sama
  2. Hitung poligon yang merupakan gabungan dari lingkaran yang didekati
  3. Hitung luas poligon yang digabungkan

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.


2

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.



1

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.


0

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.

Maaf untuk link ke foto, karena saya tidak bisa memposting gambar. (Poin reputasi tidak 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!!!

Bahkan kasus ketika sebuah lingkaran tidak berpotongan dengan yang lain juga diurus.

Ini adalah tautan GitHub ke Kode C ++ saya


-1

Pendekatan lukisan-piksel (seperti yang disarankan oleh @Loadmaster) lebih unggul daripada solusi matematika dalam berbagai cara:

  1. Implementasinya jauh lebih sederhana. Masalah di atas dapat diselesaikan dalam waktu kurang dari 100 baris kode, seperti yang ditunjukkan oleh solusi JSFiddle ini (sebagian besar karena secara konseptual jauh lebih sederhana, dan tidak memiliki kasus tepi atau pengecualian untuk ditangani).
  2. Itu mudah beradaptasi dengan masalah yang lebih umum. Ia bekerja dengan bentuk apa pun, apa pun morfologinya, selama dapat dirender dengan pustaka gambar 2D (yaitu, "semuanya!") - lingkaran, elips, splines, poligon, apa saja. Heck, bahkan gambar bitmap.
  3. Kompleksitas solusi lukisan-piksel adalah ~ O [n], dibandingkan dengan ~ O [n * n] untuk solusi matematika. Ini berarti ini akan bekerja lebih baik dengan bertambahnya jumlah bentuk.
  4. Dan berbicara tentang kinerja, Anda akan sering mendapatkan akselerasi perangkat keras secara gratis, karena sebagian besar perpustakaan 2D modern (seperti kanvas HTML5, saya percaya) akan memindahkan pekerjaan rendering ke akselerator grafis.

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.

<p>Area computation of arbitrary figures as done thru pixel-painting, in which a complex shape is drawn into an HTML5 canvas and the area determined by comparing the number of white pixels found in the resulting bitmap.  See javascript source for details.</p>

<canvas id="canvas" width="80" height="100"></canvas>

<p>Area = <span id="result"></span></p>
// Get HTML canvas element (and context) to draw into
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

// Lil' circle drawing utility
function circle(x,y,r) {
  ctx.beginPath();
  ctx.arc(x, y, r, 0, Math.PI*2);
  ctx.fill();
}

// Clear canvas (to black)
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);

// Fill shape (in white)
ctx.fillStyle = 'white';
circle(40, 50, 40);
circle(40, 10, 10);
circle(25, 15, 12);
circle(35, 90, 10);

// Get bitmap data
var id = ctx.getImageData(0, 0, canvas.width, canvas.height);
var pixels = id.data; // Flat array of RGBA bytes

// Determine area by counting the white pixels
for (var i = 0, area = 0; i < pixels.length; i += 4) {
  area += pixels[i]; // Red channel (same as green and blue channels)
}

// Normalize by the max white value of 255
area /= 255;

// Output result
document.getElementById('result').innerHTML = area.toFixed(2);

Solusi ini gagal memperhitungkan perhitungan matematika dengan luas lingkaran. Itu meleset dari inti pertanyaan OP. Sangat sering geometri rendering hanya separuh pertempuran ketika berhadapan dengan bentuk geometris
Steve
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.