Menemukan Area Eksklusif di Persimpangan Lingkaran

17

Inilah teka-teki geometri yang menantang untuk Anda!

Diberikan lingkaran A, dan nlingkaran lainnya B[n], temukan total area yang terkandung di dalamnya Ayang tidak ada di dalam lingkaran B.

Kode Anda harus sesingkat mungkin.

Memasukkan

Masukan Anda harus berisi informasi berikut:

  • Angka floating-point untuk mewakili jari-jari lingkaran A.
  • Daftar angka floating-point untuk mewakili jari-jari lingkaran di B.
  • Daftar pusat lingkaran di B. Program Anda mungkin mengharapkan pusat dalam koordinat kutub atau Cartesian.
  • Secara opsional, Anda dapat menerima jumlah nlingkaran di B. Input ini tidak diperlukan.

Harus diasumsikan bahwa pusat lingkaran Aadalah asal, yaitu titik (0, 0).

Dijamin tidak ada dua lingkaran Byang identik, tetapi tidak dijamin bahwa: semua lingkaran Bberpotongan A, semua pusat Bberada di luar A, atau tidak ada dua lingkaran yang Bsaling berpotongan. Pastikan solusi Anda dapat menangani berbagai kasus tepi.

Anda dapat menerima input dalam urutan apa pun, dan dalam bentuk input teks (melalui stdin atau bahasa Anda yang setara), parameter fungsi, atau argumen baris perintah.

Jika Anda memilih untuk menerima input teks, harus ada satu atau dua karakter pembatas ASCII yang dapat dicetak di antara potongan input.

Keluaran

Program atau fungsi Anda harus menampilkan angka floating-point tunggal yang mewakili area total Atidak dalam lingkaran mana pun di B. Jawaban Anda harus akurat untuk setidaknya tiga angka penting untuk semua kasus uji.

Aturan umum berlaku.

Solusi Anda tidak harus bergantung pada titik pengambilan sampel dalam lingkaran untuk menentukan area.

Built-in yang secara otomatis menemukan persimpangan lingkaran, menemukan area dalam persimpangan lingkaran, atau menyelesaikan masalah ini segera dilarang.

Uji Kasus

Di setiap gambar, lingkaran Adiuraikan dalam warna biru, dengan lingkaran yang Bdiuraikan dalam hijau dan diisi hitam. Area yang harus dikembalikan diisi merah.

(Terima kasih khusus kepada Rainer P. untuk memeriksa solusi saya)

Uji kasus 1:

A = {x: 0, y: 0, rad: 50}
B[0] = {x: 0, y: 0, rad: 100}

Test case 1

Result: 0.00

Uji kasus 2:

A = {x: 0, y: 0, rad: 100.000000}
B[0] = {x: 100.000000, y: 0.000000, rad: 50.000000}
B[1] = {x: 30.901699, y: -95.105652, rad: 50.000000}
B[2] = {x: -80.901699, y: -58.778525, rad: 50.000000}
B[3] = {x: -80.901699, y: 58.778525, rad: 50.000000}
B[4] = {x: 30.901699, y: 95.105652, rad: 50.000000}

Test case 2

Result: 1.3878e+04

Uji kasus 3:

A = {x: 0, y: 0, rad: 138}
B[0] = {x: 100, y: 0, rad: 100}
B[1] = {x: -50, y: -86, rad: 100} 
B[2] = {x: -93, y: 135, rad: 50}

Test case 3

Result: 1.8969e+04

Uji kasus 4:

A = {x: 0, y: 0, rad: 121.593585}
B[0] = {x: 81.000000, y: 107.000000, rad: 59.841457}
B[1] = {x: -152.000000, y: -147.000000, rad: 50.000000}
B[2] = {x: 43.000000, y: -127.000000, rad: 105.118980}
B[3] = {x: 0.000000, y: -72.000000, rad: 57.870545}
B[4] = {x: -97.000000, y: -81.000000, rad: 98.488578}
B[5] = {x: -72.000000, y: 116.000000, rad: 66.468037}
B[6] = {x: 2.000000, y: 51.000000, rad: 50.000000}

Test case 4

Result: 1.1264e+04

Uji kasus 5:

A = {x: 0, y: 0, rad: 121.605921}
B[0] = {x: 0.000000, y: -293.000000, rad: 250.000000}
B[1] = {x: 0.000000, y: -56.000000, rad: 78.230429}
B[2] = {x: 0.000000, y: -102.000000, rad: 100.000000}

Test case 5

Result: 2.6742e+04

Bacaan yang disarankan:

Fewell, MP "Area Tumpang tindih Umum Tiga Lingkaran." Oktober 2006. Web. http://dspace.dsto.defence.gov.au/dspace/bitstream/1947/4551/4/DSTO-TN-0722.PR.pdf .

BrainSteel
sumber
Saya mencoba menyelesaikan ini sendiri dua tahun lalu ketika mengerjakan ini , berdasarkan betapa sederhananya masalah untuk dua lingkaran. Saya akhirnya membaca koran yang Anda tautkan ... dan memutuskan untuk pergi bersama Monte Carlo di daerah itu. "Solusi Anda tidak harus bergantung pada titik pengambilan sampel dalam lingkaran untuk menentukan area." D:
Martin Ender
Anda sepertinya tidak memiliki test case di mana satu lingkaran Bberisi yang lain. Mungkin perlu ditambahkan.
Martin Ender
Bisakah Anda memeriksa test case ketiga Anda? Saya mengerti 1.8970e+04.
LegionMammal978
@ MartinBüttner Saya juga menemukan masalah secara tidak sengaja. Saya tidak terlalu senang dengan solusi saya, tetapi tampaknya berhasil. Saya akan mencoba untuk membuat tes kecil untuk kasus itu, terima kasih!
BrainSteel
@ LegionMammal978 Ya, sepertinya case itu salah. Saya memiliki data sebagai berikut untuk persimpangan antara lingkaran: B[0] - A intersection: 20653.659515, B[1] - A intersection: 20757.824115, B[1] - B[0] intersection: 1841.847766, B[2] - A intersection: 1289.164541, yang menghasilkan 18969.69009sebagai jawabannya.
BrainSteel

Jawaban:

14

Python 2, 631 byte

from cmath import*
C=input()
O,R=C[0]
def I(p,r,q,s):
 try:q-=p;d=abs(q*q);x=(r*r-s*s+d)/d/2;return[p+q*(x+z*(r*r/d-x*x)**.5)for z in-1j,1j]
 except:return[]
S=sorted
V=S(i.real for p,r in C for c in C for i in[p-r,p+r]+I(p,r,*c)if-R<=(i-O).real<=R)
A=pi*R*R
for l,r in zip(V,V[1:]):
 H=[]
 for p,t in C:
    try:
     for s in-1,1:a,b=[p.imag+s*(t*t-(p.real-x)**2)**.5for x in l,r];H+=[a+b,a,b,s,t,p],
    except:0
 a,b=H[:2];H=S(H[2:]);n=0;c=a
 for d in H:
    s=d[3];z=.5;H*=d<b
    for q,w,e,_,t,y in(c,min(d,b))*(n-s<(a<d)or[0]*n>H):\
g=phase((l+w*1j-y)/(r+e*1j-y));A-=abs(g-sin(g)).real*t*t/2-z*q*(r-l);z=-z
    n-=s
    if(a<d)*s*n==-1:c=d
print A

Line-break yang didahului oleh \adalah untuk membaca mudah, dan tidak dihitung dalam skor.

Membaca input melalui STDIN sebagai daftar (center, radius)pasangan, di mana centerada bilangan kompleks dalam formulir X+Yj. Lingkaran pertama dalam daftar adalah A (yang pusatnya tidak harus berada di titik asal), dan sisanya dari daftar adalah B . Mencetak hasilnya ke STDOUT.

Contoh

Input:  (0+0j, 138),  (100+0j, 100), (-50+-86j, 100), (-93+135j, 50)
Output: 18969.6900901

Penjelasan

Ini adalah variasi (lebih lama, dan lebih jelek: P) pada solusi saya untuk area Martin Büttner dari tantangan Self-Intersecting Polygon . Ia menggunakan trik yang sama untuk memecah masalah menjadi beberapa bagian yang cukup kecil, yang menjadi lebih mudah dikelola.

Kami menemukan titik-titik persimpangan antara semua pasangan lingkaran (mempertimbangkan A , dan lingkaran di B ), dan melewati garis vertikal melalui masing-masing pasangan. Selain itu, kami melewati semua garis vertikal yang bersinggungan dengan salah satu lingkaran. Kami membuang semua garis yang tidak berpotongan A , sehingga semua garis yang tersisa antara garis singgung kiri dan kanan dari A .

Gambar 1

Kami mencari area persimpangan A dan penyatuan lingkaran di B — area merah gelap pada ilustrasi di atas. Ini adalah area yang harus kita kurangi dari A untuk mendapatkan hasilnya.

Di antara setiap pasangan garis vertikal berturut-turut, area ini dapat dipecah menjadi seperangkat trapesium vertikal (atau segitiga, atau segmen garis, sebagai kasing khusus trapesium), dengan segmen busur "berlebih" di sebelah setiap kaki. Fakta bahwa kita melewati garis vertikal sebanyak yang kita lakukan menjamin bahwa area yang dibatasi memang tidak lebih rumit dari itu, karena jika tidak akan ada titik persimpangan tambahan, dan karenanya garis vertikal tambahan, antara dua garis di pertanyaan.

Gambar 2

Untuk menemukan trapezoid dan segmen busur ini, untuk setiap pasangan garis vertikal berturut-turut, kami menemukan segmen arc dari masing-masing lingkaran yang terletak di antara kedua garis ini (tentu saja, beberapa lingkaran mungkin tidak memiliki segmen busur antara sepasang garis yang diberikan .) Pada ilustrasi di bawah ini, ini adalah enam segmen busur kuning (terang dan gelap), ketika mempertimbangkan dua garis vertikal merah. Perhatikan bahwa, karena kami meneruskan semua garis vertikal yang bersinggungan ke lingkaran, jika lingkaran memiliki segmen busur di antara dua garis, itu harus memotong kedua garis, yang menyederhanakan sisa algoritma.

Tidak semua busur ini relevan; kita hanya tertarik pada orang-orang yang berada di batas persimpangan antara A dan persatuan B . Untuk menemukan itu, kami mengurutkan busur dari atas ke bawah (perhatikan bahwa busur mungkin tidak saling berpotongan dengan benar, karena ini akan menyiratkan adanya garis vertikal lain antara keduanya yang sedang kami pertimbangkan, sehingga masuk akal untuk berbicara tentang busur sembarang yang berada di atas, atau di bawah, busur lainnya.)

Gambar 3

Kami melintasi busur, secara berurutan, sambil tetap menghitung jumlah lingkaran B yang saat ini kami di dalam, n . Jika n berubah dari 0 menjadi 1 saat kita berada di dalam A , atau jika kita berada di busur atas A sementara n adalah nol, maka busur saat ini sesuai dengan satu kaki trapesium. Jika n berubah dari 1 menjadi 0 saat kita berada di dalam A , atau jika kita berada di busur bawah A saat nadalah nol, maka busur saat ini sesuai dengan kaki lain dari trapesium yang sama. Setelah kita menemukan sepasang seperti busur (dua busur kuning cerah dalam ilustrasi di atas), kami menghitung luas yang sesuai trapesium, dan dari dua segmen busur, dan menambahkannya ke daerah total yang harus dikurangkan dari A .

Menghitung area A , serta area trapesium, cukup lurus ke depan. Luas setiap segmen busur adalah luas sektor lingkaran yang sesuai, dikurangi luas segitiga yang simpulnya adalah dua titik akhir segmen busur, dan pusat lingkaran yang sesuai.

Gambar 4

Elo
sumber
1
Ini adalah jenis solusi yang saya pertimbangkan, kecuali saya akan menemukan area target secara langsung dengan menemukan triarcs dan trapearc yang berada di A tetapi bukan B (yang area-nya harus ditemukan dengan mengurangi segmen busur dari segitiga atau trapesium).
kuintopia
@quintopia Ini bahkan mungkin sedikit lebih pendek, karena menghemat kita untuk menghitung luas A , dan yang diperlukan hanyalah bermain sedikit dengan kondisi pada n .
Ell
@quintopia OTOH, Anda harus memperhitungkan kemungkinan memiliki busur positif di sebelah salah satu kaki, jika itu merupakan segmen busur A , jadi siapa tahu ...
Ell
Solusi yang sangat baik. Masalah yang hampir identik dengan ini terjebak di kepala saya tadi malam, dan saya benar-benar ingin seseorang untuk menyelesaikannya. Solusi Anda lebih baik daripada ide-ide yang saya kerjakan.
Logic Knight