Trovare un'area esclusiva nelle intersezioni Circle


17

Ecco un puzzle di geometria ingannevolmente stimolante per te!

Dato un cerchio Ae naltri cerchi B[n], trova l'area totale contenuta all'interno Ache non è all'interno di alcun cerchio di B.

Il tuo codice dovrebbe essere il più breve possibile.

Ingresso

Il tuo input dovrebbe contenere le seguenti informazioni:

  • Un numero in virgola mobile per rappresentare il raggio del cerchio A.
  • Un elenco di numeri in virgola mobile per rappresentare i raggi dei cerchi in B.
  • Un elenco dei centri dei cerchi in B. Il tuo programma potrebbe prevedere i centri in coordinate polari o cartesiane.
  • Facoltativamente, potresti ricevere il numero ndi cerchi in B. Questo input non è richiesto.

Si presume che il centro del cerchio Asia l'origine, cioè il punto (0, 0).

È garantito che non esistono due cerchi in Bsono identiche, ma è non assicurata: tutti i cerchi di Bintersezione A, tutti i centri di Bsono fuori A, o nessun due cerchi in Bintersecano reciprocamente. Assicurati che la tua soluzione sia in grado di gestire vari casi limite.

È possibile ricevere input in qualsiasi ordine e sotto forma di input di testo (tramite stdin o l'equivalente della propria lingua), parametri di funzione o argomenti della riga di comando.

Se si sceglie di ricevere input di testo, dovrebbero essere presenti delimitatori ASCII stampabili a uno o due caratteri tra le parti di input.

Produzione

Il tuo programma o funzione dovrebbe generare un singolo numero in virgola mobile che rappresenta l'area totale di Anon all'interno di nessuno dei cerchi di B. Le risposte devono essere accurate per almeno tre cifre significative per tutti i casi di test.

Si applicano le regole generali di .

La tua soluzione non dovrebbe fare affidamento su punti di campionamento all'interno dei cerchi per determinare un'area.

Gli built-in che individuano automaticamente le intersezioni dei cerchi, trovano aree all'interno delle intersezioni dei cerchi o risolvono immediatamente questo problema non sono consentiti.

Casi test

In ogni immagine, il cerchio Aè delineato in blu, con i cerchi Bdelineati in verde e riempiti di nero. L'area che deve essere restituita è riempita in rosso.

(Un ringraziamento speciale a Rainer P. per aver verificato le mie soluzioni)

Caso di prova 1:

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

Caso di prova 1

Result: 0.00

Caso di prova 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}

Caso di prova 2

Result: 1.3878e+04

Caso di prova 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}

Caso di prova 3

Result: 1.8969e+04

Caso di prova 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}

Caso di prova 4

Result: 1.1264e+04

Caso di prova 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}

Caso di prova 5

Result: 2.6742e+04

Letture consigliate:

Fewell, MP "Area di sovrapposizione comune di tre cerchi". Ottobre 2006. Web. http://dspace.dsto.defence.gov.au/dspace/bitstream/1947/4551/4/DSTO-TN-0722.PR.pdf .


Ho provato a risolverlo da solo due anni fa mentre ci lavoravo , basandomi su quanto sia semplice il problema per due cerchi. Ho finito per leggere il documento che hai collegato ... e ho deciso di andare con Monte Carlo nella zona. "La tua soluzione non dovrebbe fare affidamento su punti di campionamento all'interno dei cerchi per determinare un'area". D:
Martin Ender,

Sembra che tu non abbia un caso di prova in cui un cerchio ne Bcontiene un altro. Potrebbe valere la pena aggiungerlo.
Martin Ender,

Potresti controllare il tuo terzo caso di test? Sto ottenendo 1.8970e+04.
LegionMammal978,

@ MartinBüttner Anche io ho riscontrato il problema per caso. Non sono troppo soddisfatto della mia soluzione, ma sembra funzionare. Proverò a fare un piccolo test per quel caso, grazie!
BrainSteel,

@ LegionMammal978 Sì, sembra che il caso sia sbagliato. Ho i seguenti dati per intersezioni tra gli ambienti: 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, che produce 18969.69009come risposta.
BrainSteel,

Risposte:


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

Le interruzioni di riga precedute da \sono di facile lettura e non vengono conteggiate nel punteggio.

Legge l'input tramite STDIN come un elenco di (center, radius)coppie, in cui centerè presente un numero complesso nel modulo X+Yj. Il primo cerchio della lista è un (il cui centro non deve essere all'origine), e il resto della lista è B . Stampa il risultato su STDOUT.

Esempio

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

Spiegazione

Questa è una variazione (più lunga e molto più brutta: P) della mia soluzione alla sfida Area del poligono autointersidente di Martin Büttner . Usa lo stesso trucco per scomporre il problema in pezzi abbastanza piccoli, per i quali diventa più gestibile.

Troviamo i punti di intersezione tra tutte le coppie di cerchi (considerando sia A , sia i cerchi in B ) e passiamo una linea verticale attraverso ciascuno di essi. Inoltre, passiamo tutte le linee verticali tangenti a uno qualsiasi dei cerchi. Gettiamo via tutte le linee che non si intersecano A , in modo che tutte le righe rimanenti sono tra le tangenti a destra ea sinistra di A .

Figura 1

Stiamo cercando l'area dell'intersezione di A e l'unione dei cerchi in B , l'area rosso scuro nell'illustrazione sopra. Questa è l'area che dobbiamo sottrarre da A per ottenere il risultato.

Tra ogni coppia di linee verticali consecutive, quest'area può essere suddivisa in una serie di trapezi (o triangoli o segmenti di linea verticali), come casi speciali di trapezi, con un arco "in eccesso" accanto a ciascuna gamba. Il fatto che attraversiamo tante linee verticali quante ne facciamo garantisce che l'area delimitata non sia effettivamente più complicata di così, poiché altrimenti dovrebbe esserci un ulteriore punto di intersezione, e quindi una linea verticale aggiuntiva, tra le due linee in domanda.

figura 2

Per trovare questi trapezi e segmenti di arco, per ogni coppia di linee verticali consecutive, troviamo i segmenti di arco di ciascuno dei cerchi che si trovano correttamente tra queste due linee (ovviamente, alcuni cerchi potrebbero non avere alcun segmento di arco tra una data coppia di linee .) Nell'illustrazione seguente, questi sono i sei segmenti di arco giallo (chiaro e scuro), se si considerano le due linee verticali rosse. Si noti che, poiché passiamo tutte le linee verticali tangenti ai cerchi, se un cerchio ha un segmento di arco tra le due linee, interseca necessariamente entrambe le linee, il che semplifica il resto dell'algoritmo.

Non tutti questi archi sono rilevanti; siamo interessati solo a quelli che sono al confine della intersezione tra A e l'unione di B . Per trovarli, ordiniamo gli archi dall'alto verso il basso (nota che gli archi potrebbero non intersecarsi correttamente tra loro, poiché ciò implicherebbe l'esistenza di un'altra linea verticale tra i due che stiamo prendendo in considerazione, e quindi ha senso parlare di un arco arbitrario sopra o sotto qualsiasi altro).

Figura 3

Attraversiamo gli archi, in ordine, tenendo conto del numero di cerchi B in cui ci troviamo attualmente, n . Se n cambia da 0 a 1 mentre siamo all'interno di A , o se siamo nell'arco superiore di A mentre n è diverso da zero, allora l'arco corrente corrisponde a una gamba di un trapezio. Se n cambia da 1 a 0 mentre siamo all'interno di A , o se siamo nell'arco inferiore di A mentre nè diverso da zero, quindi l'arco corrente corrisponde all'altra gamba dello stesso trapezio. Una volta che troviamo una coppia di archi (due archi gialli luminosi nella figura precedente), si calcola l'area del trapezio corrispondente, e dei due segmenti di arco, e aggiungerlo alla superficie totale da sottrarre A .

Il calcolo dell'area di A , nonché delle aree dei trapezi, è abbastanza semplice. L'area di ciascun segmento di arco è l'area del settore circolare corrispondente, meno l'area del triangolo i cui vertici sono i due punti finali del segmento di arco e il centro del cerchio corrispondente.

Figura 4


1
Questo è il tipo di soluzione che stavo prendendo in considerazione, tranne per il fatto che avrei trovato direttamente l'area di destinazione trovando i triarchi e i trapearc che erano in A ma non B (le cui aree devono essere trovate sottraendo un segmento di arco da un triangolo o un trapezio).
Quintopia,

@quintopia Questo potrebbe anche essere un po 'più breve, dal momento che ci fa risparmiare la necessità di calcolare l'area di A , e probabilmente tutto ciò che serve è giocare un po' con la condizione su n .
Ell

@quintopia OTOH, dovrai tenere conto della possibilità di avere un arco positivo accanto a una delle gambe, se si tratta di un segmento di arco di A , quindi chissà ...
Ell

Soluzione eccellente Un problema quasi identico a questo è stato bloccato nella mia testa ieri sera e volevo davvero che qualcuno lo risolvesse. La tua soluzione è migliore delle idee con cui stavo lavorando.
Logic Knight,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.