Area combinata di cerchi sovrapposti


107

Recentemente mi sono imbattuto in un problema in cui avevo quattro cerchi (punti medi e raggio) e dovevo calcolare l'area dell'unione di questi cerchi.

Immagine di esempio:

Per due cerchi è abbastanza facile,

Posso solo calcolare la frazione dell'area di ciascun cerchio che non è all'interno dei triangoli e quindi calcolare l'area dei triangoli.

Ma esiste un algoritmo intelligente che posso usare quando ci sono più di due cerchi?


15
Questo è un problema davvero interessante, ricordo di averlo visto durante le lezioni di geometria delle scuole superiori, ma non ho mai trovato una soluzione. Se non riesci a trovare una risposta qui, prova a pubblicarla su mathoverflow.net e lascia che i matematici ci provino : P
Charles Ma,

25
a volte i veri programmatori hanno bisogno di vera matematica
fa.

1
Che ne dici di trovare la risposta a questa domanda: "Abbiamo rappresentanti di vendita che vivono in queste 4 località, ognuno dei quali serve un'area con questi 4 raggi. Quanto del paese copriamo?" Se avevi un database in continua evoluzione di rappresentanti di vendita, questa diventa una domanda di programmazione!
Chris Roberts,

5
In realtà, questo è il tipo di problema a cui piace pensare ai veri programmatori.
MAK

2
@zvolkov: i circuiti stampati sono descritti con un linguaggio che fa cadere quadrati e cerchi verso il basso e, facoltativamente, li trascina. "Calcola l'area del rame". (Questo può essere necessario per calcolare i tempi di incisione, sapere se aggiungere opere d'arte scavenging, varie cose.)
DigitalRoss,

Risposte:


97

Trova tutte le intersezioni dei cerchi sul perimetro esterno (es. B, D, F, H nel diagramma seguente). Collegali insieme ai centri dei cerchi corrispondenti per formare un poligono. L'area dell'unione dei cerchi è l'area del poligono + l'area delle fette di cerchio definita da punti di intersezione consecutivi e il centro del cerchio tra di loro. Dovrai anche tenere conto di eventuali buchi.

sovrapposizione del cerchio


17
Cosa succede quando c'è un buco al centro?
John Gietzen

3
Dovrai sottrarre il poligono collegato al centro per il foro dal totale e aggiungere le fette di cerchio per quel poligono al totale.
Ants Aasma

3
bello ma immagino che questo richiederà molti dettagli di implementazione per gestire tutti i casi speciali (cerchio dentro l'altro, nessuna intersezione, buchi, un punto di contatto ...)
fa.

1
I casi speciali sono piuttosto semplici. I cerchi all'interno di altri vengono scartati non avendo intersezioni perimetrali. Un punto di contatto è in effetti due intersezioni con distanza zero. Le forme disconnesse possono essere trovate tramite l'algoritmo dei componenti collegati sul grafico in cui due cerchi sono collegati se la distanza dei centri è inferiore alla somma dei raggi. I fori sono tutti poligoni eccetto quello con l'area più grande. Le intersezioni perimetrali sono tutte le intersezioni che non sono strettamente all'interno di alcun cerchio.
Ants Aasma

4
sì, ma i bordi dei fori sono anche (piccoli) archi. Penso ancora che questo abbia bisogno di molto codice per funzionare bene.
fa.

32

Sono sicuro che ci sia un algoritmo intelligente, ma eccone uno stupido per evitare di doverlo cercare;

  • metti un riquadro di delimitazione attorno ai cerchi;
  • generare punti casuali all'interno del riquadro di delimitazione;
  • capire se il punto casuale si trova all'interno di uno dei cerchi;
  • calcola l'area con qualche semplice addizione e divisione (proporzione_di_punti_interno * area_of_bounding_box).

Certo è stupido, ma:

  • puoi ottenere una risposta precisa quanto desideri, genera solo più punti;
  • funzionerà per tutte le forme per le quali è possibile calcolare la distinzione interno / esterno;
  • si parallelizzerà magnificamente in modo da poter utilizzare tutti i core.

2
Questo funzionerà, ma i metodi Monte-Carlo come questo, basati semplicemente sul campionamento uniforme, generalmente non hanno i migliori tassi di convergenza.
ShreevatsaR

2
Scusa, ma anche se apprezzo il tuo impegno e penso che la tua soluzione sia "praticamente utilizzabile", ritengo che il tuo approccio sia molto sbagliato. Questo è un problema che può e deve essere risolto con la matematica, non con la forza bruta. Sprecare energia e nucleo per problemi come questo è dispendioso e generoso.
mafu

5
Hai ragione, mi vergogno di me stesso, ma ho un cluster con 12.000 core, posso permettermi di essere prodigo. E non riesco a capire come far scalare l'elegante soluzione matematica a così tanti processori.
High Performance Mark

8
Non c'è nulla di intrinsecamente sbagliato in un approccio Monte-Carlo (o qualsiasi altro randomizzato), a condizione che dia il grado di accuratezza richiesto e lo faccia in un ragionevole lasso di tempo.
MAK

@mafutrct, hai sicuramente ragione. Tuttavia, è facile fare piccoli errori in matematica. Questa soluzione fornisce un modo semplice per verificare la correttezza.
Richard

18

La risposta di Ants Aasma ha dato l'idea di base, ma volevo renderla un po 'più concreta. Dai un'occhiata ai cinque cerchi sottostanti e al modo in cui sono stati scomposti.

Esempio

  • I punti blu sono i centri del cerchio.
  • I punti rossi sono le intersezioni dei confini del cerchio.
  • I punti rossi con l'interno bianco sono intersezioni del confine del cerchio che non sono contenute in nessun altro cerchio .

Identificare questi 3 tipi di punti è facile. Ora costruisci una struttura dati del grafico in cui i nodi sono i punti blu ei punti rossi con l'interno bianco. Per ogni cerchio, metti un bordo tra il centro del cerchio (punto blu) e ciascuna delle sue intersezioni (punti rossi con interno bianco) sul suo confine.

Questo scompone l'unione circolare in una serie di poligoni (ombreggiati in blu) e pezzi di torta circolari (ombreggiati in verde) che sono disgiunti a due a due e coprono l'unione originale (cioè una partizione). Poiché ogni pezzo qui è qualcosa di cui è facile calcolare l'area, puoi calcolare l'area dell'unione sommando le aree dei pezzi.


Penso di poter calcolare un insieme di punti rosso / bianco abbastanza facilmente, tuttavia la mia teoria dei grafi non è troppo grande: algoritmicamente, come si arriva da un elenco di nodi + bordi a un'area calcolata?
user999305

1
L'algoritmo può essere semplificato utilizzando un insieme di triangoli non sovrapposti invece di poligoni. Gli archi (aree verdi) sono aree contenute in un solo cerchio. Aumenta la dimensione di un poligono aggiungendo più cerchi. (alla fine puoi dimenticarti di parlare persino di poligoni). Rende le proprietà booleane e anche le aree sono più facili da calcolare. Quando un punto rosso vuoto diventa un punto rosso pieno, aggiungi semplicemente più triangoli al tuo set e regola l'arco che viene "consumato" da sempre più cerchi intersecanti.
Steve

16

Per una soluzione diversa dalla precedente si potrebbe produrre una stima con una precisione arbitraria utilizzando un quadtree.

Questo funziona anche per qualsiasi unione di forme se puoi dire se un quadrato è all'interno o all'esterno o se interseca la forma.

Ogni cella ha uno degli stati: vuoto, pieno, parziale

L'algoritmo consiste nel "disegnare" i cerchi del quadrialbero partendo da una bassa risoluzione (4 celle ad esempio contrassegnate come vuote). Ogni cella è:

  • all'interno di almeno un cerchio, quindi contrassegna la cella come piena,
  • fuori da tutti i cerchi, contrassegna la cella come vuota,
  • altrimenti segna la cella come parziale.

Al termine, è possibile calcolare una stima dell'area: le celle piene danno il limite inferiore, le celle vuote danno il limite superiore, le celle parziali danno il massimo errore di area.

Se l'errore è troppo grande per te, affina le celle parziali fino a ottenere la giusta precisione.

Penso che questo sarà più facile da implementare rispetto al metodo geometrico che potrebbe richiedere di gestire molti casi speciali.


3
La mia ipotesi è che questo converga più rapidamente dell'algoritmo del punto interno / esterno di monte carlo.
Frank Krueger

Questo sembra molto più facile da implementare. Sicuramente il miglior metodo di forza bruta suggerito. Grazie!
Anton Hansson

la forza bruta qui è chiamata teorema di compressione
fa.

Questo è il tipo di algoritmo che usi nell'aritmetica degli intervalli. en.wikipedia.org/wiki/Interval_arithmetic
rjmunro

13

Adoro l'approccio al caso di 2 cerchi che si intersecano: ecco come utilizzerei una leggera variazione dello stesso approccio per l'esempio più complesso.

Potrebbe fornire una migliore comprensione della generalizzazione dell'algoritmo per un numero maggiore di cerchi semi-sovrapposti.

La differenza qui è che inizio collegando i centri (quindi c'è un vertice tra il centro dei cerchi, piuttosto che tra i punti in cui i cerchi si intersecano) penso che questo permetta di generalizzare meglio.

(in pratica, forse vale la pena il metodo monte-carlo)

testo alternativo
(fonte: secretGeek.net )


1
Penso che fare il tipo di divisione poligonale suggerito dalla tua immagine sarebbe probabilmente un ottimo approccio. Ci sono molti dettagli da elaborare per codificarlo. Come gestirebbe una catena di venti cerchi, ognuno dei quali si sovrappone solo all'ultimo e al successivo della catena? Facile da capire a mano, ma qual è il tuo algoritmo?
PeterAllenWebb

4

Se vuoi una risposta discreta (anziché continua), potresti fare qualcosa di simile a un algoritmo di pixel painting.

Disegna i cerchi su una griglia, quindi colora ogni cella della griglia se è contenuta principalmente all'interno di un cerchio (cioè, almeno il 50% della sua area è all'interno di uno dei cerchi). Fallo per l'intera griglia (dove la griglia copre tutta l'area coperta dai cerchi), quindi conta il numero di celle colorate nella griglia.


3

Hmm, problema molto interessante. Il mio approccio sarebbe probabilmente qualcosa sulla falsariga di quanto segue:

  • Trova un modo per capire quali sono le aree di intersezione tra un numero arbitrario di cerchi, cioè se ho 3 cerchi, devo essere in grado di capire qual è l'intersezione tra quei cerchi. Il metodo "Monte-Carlo" sarebbe un buon modo per approssimarlo ( http://local.wasp.uwa.edu.au/~pbourke/geometry/circlearea/ ).
  • Elimina tutti i cerchi contenuti interamente in un altro cerchio più grande (guarda il raggio e il modulo della distanza tra il centro dei due cerchi) non credo sia obbligatorio.
  • Scegli 2 cerchi (chiamali A e B) e calcola l'area totale usando questa formula:

(questo è vero per qualsiasi forma, che sia cerchio o altro)

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

Dove A ∪ Bsignifica A unione B e A ∩ Bsignifica A interseca B (puoi risolverlo dal primo passaggio.

  • Ora continua ad aggiungere cerchi e continua a elaborare l'area aggiunta come somma / sottrazione di aree di cerchi e aree di intersezioni tra cerchi. Ad esempio per 3 cerchi (chiama il cerchio extra C) calcoliamo l'area usando questa formula:

(Questo è lo stesso di sopra dove Aè stato sostituito con A∪B)

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

Dove area(A∪B)abbiamo appena risolto e area((A∪B)∩C)può essere trovato:

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)

Dove di nuovo puoi trovare l'area (A∩B∩C) dall'alto.

La parte complicata è l'ultimo passaggio: più cerchi vengono aggiunti più diventa complesso. Credo che ci sia un'espansione per elaborare l'area di un'intersezione con un'unione finita, o in alternativa potresti essere in grado di elaborarla ricorsivamente.

Anche per quanto riguarda l'utilizzo di Monte-Carlo per approssimare l'area di itersione, credo che sia possibile ridurre l'intersezione di un numero arbitrario di cerchi all'intersezione di 4 di quei cerchi, che può essere calcolata esattamente (non ho idea di come farlo però).

Probabilmente c'è un modo migliore per farlo: la complessità aumenta in modo significativo (possibilmente in modo esponenziale, ma non ne sono sicuro) per ogni cerchio aggiuntivo aggiunto.


Che succede con la formattazione? Mi dispiace anche per l'uso di n e u per l'intersezione e l'unione, probabilmente c'è un modo migliore ...
Justin

1
aggiunti alcuni segni di unione unicode (unic) e intersezione (∩). si spera che funzionino.
Spoike

3

Ho lavorato su un problema di simulazione di campi stellari sovrapposti, tentando di stimare il conteggio delle stelle reali dalle aree del disco effettive in campi densi, dove le stelle luminose più grandi possono mascherare quelle più deboli. Anch'io speravo di poterlo fare con una rigorosa analisi formale, ma non sono riuscito a trovare un algoritmo per il compito. L'ho risolto generando i campi stellari su sfondo blu come dischi verdi, il cui diametro era determinato da un algoritmo di probabilità. Una semplice routine può accoppiarli per vedere se c'è una sovrapposizione (facendo diventare gialla la coppia di stelle); quindi un conteggio dei pixel dei colori genera l'area osservata da confrontare con l'area teorica. Questo genera quindi una curva di probabilità per i conteggi reali. Forse la forza bruta, ma sembra funzionare bene. (fonte: 2from.com )


2

Ecco un algoritmo che dovrebbe essere facile da implementare nella pratica e potrebbe essere regolato per produrre un errore arbitrariamente piccolo:

  1. Approssimare ogni cerchio da un poligono regolare centrato nello stesso punto
  2. Calcola il poligono che è l'unione dei cerchi approssimati
  3. Calcola l'area del poligono unito

I passaggi 2 e 3 possono essere eseguiti utilizzando algoritmi standard e facili da trovare dalla geometria computazionale.

Ovviamente, più lati usi per ogni poligono approssimativo, più vicina all'esatta sarebbe la tua risposta. Potresti approssimare usando poligoni inscritti e circoscritti per ottenere limiti sulla risposta esatta.


2

Esistono soluzioni efficienti a questo problema utilizzando i cosiddetti diagrammi di potenza. Questa è matematica davvero pesante e non è qualcosa che vorrei affrontare improvvisamente. Per una soluzione "facile", cerca algoritmi di sweep di linea. Il principio di base qui è quello di dividere la figura in strisce, dove calcolare l'area in ciascuna striscia è relativamente facile.

Quindi, sulla figura che contiene tutti i cerchi senza nulla cancellato, traccia una linea orizzontale in ogni posizione che è la parte superiore di un cerchio, la parte inferiore di un cerchio o l'intersezione di 2 cerchi. Notare che all'interno di queste strisce, tutte le aree necessarie per il calcolo hanno lo stesso aspetto: un "trapezio" con due lati sostituiti da segmenti circolari. Quindi, se riesci a capire come calcolare una forma del genere, fallo per tutte le singole forme e sommale. La complessità di questo approccio ingenuo è O (N ^ 3), dove N è il numero di cerchi nella figura. Con un uso intelligente della struttura dei dati, potresti migliorare questo metodo di sweep di riga in O (N ^ 2 * log (N)), ma a meno che non sia davvero necessario, probabilmente non vale la pena.



1

A seconda del problema che stai cercando di risolvere, potrebbe essere sufficiente ottenere un limite superiore e inferiore. Un limite superiore è facile, solo la somma di tutti i cerchi. Per un limite inferiore è possibile selezionare un singolo raggio in modo che nessuno dei cerchi si sovrapponga. Per meglio trovare il raggio più grande (fino al raggio effettivo) per ogni cerchio in modo che non si sovrapponga. Dovrebbe anche essere piuttosto banale rimuovere qualsiasi cerchio completamente sovrapposto (Tutti questi cerchi soddisfano | P_a - P_b | <= r_a) dove P_a è il centro del cerchio A, P_b è il centro del cerchio B e r_a è il raggio di A ) e questo migliora sia il limite superiore che quello inferiore. Potresti anche ottenere un limite superiore migliore se usi la formula delle coppie su coppie arbitrarie anziché solo la somma di tutti i cerchi. Potrebbe esserci un buon modo per scegliere il "migliore"

Dato un limite superiore e inferiore potresti essere in grado di sintonizzare meglio un approccio Monte-carlo, ma non mi viene in mente nulla di specifico. Un'altra opzione (sempre a seconda dell'applicazione) è rasterizzare i cerchi e contare i pixel. È fondamentalmente l'approccio Monte-carlo con una distribuzione fissa.


0

Questo può essere risolto usando il teorema di Green , con una complessità di n ^ 2log (n). Se non hai familiarità con il teorema di Green e vuoi saperne di più, ecco il video e le note della Khan Academy. Ma per il bene del nostro problema, penso che la mia descrizione sarà sufficiente.

Ci scusiamo per i link alle foto, perché non posso pubblicare immagini (punti reputazione insufficienti)

Equazione generale del teorema di Green

Se metto L e M in modo tale

Condizione

quindi RHS è semplicemente l'area della Regione R e può essere ottenuto risolvendo l'integrale chiuso o LHS ed è esattamente quello che faremo.

Tutte le unioni possono essere suddivise in tali insiemi disgiunti di cerchi che si intersecano

Quindi l'integrazione lungo il percorso in senso antiorario ci dà l' Area della regione e l'integrazione lungo il senso orario ci dà il negativo dell'Area . Così

AreaOfUnion = (Integrazione lungo archi rossi in senso antiorario + Integrazione lungo archi blu in senso orario)

Ma il trucco è se per ogni cerchio, se integriamo gli archi che non sono all'interno di nessun altro cerchio, otteniamo la nostra area richiesta, cioè otteniamo l'integrazione in senso antiorario lungo tutti gli archi rossi e l'integrazione lungo tutti gli archi blu lungo la direzione oraria. LAVORO FATTO!!!

Vengono presi in considerazione anche i casi in cui un cerchio non si interseca con nessun altro.

Ecco il collegamento GitHub al mio codice C ++


-1

L'approccio pixel-painting (come suggerito da @Loadmaster) è superiore alla soluzione matematica in una varietà di modi:

  1. L'implementazione è molto più semplice. Il problema di cui sopra può essere risolto in meno di 100 righe di codice, come dimostra questa soluzione JSFiddle (principalmente perché è concettualmente molto più semplice e non ha casi limite o eccezioni da affrontare).
  2. Si adatta facilmente a problemi più generali. Funziona con qualsiasi forma, indipendentemente dalla morfologia, purché sia ​​renderizzabile con le librerie di disegno 2D (cioè, "tutte!") - cerchi, ellissi, spline, poligoni, come lo chiami. Diamine, anche immagini bitmap.
  3. La complessità della soluzione di pixel painting è ~ O [n], rispetto a ~ O [n * n] per la soluzione matematica. Ciò significa che funzionerà meglio all'aumentare del numero di forme.
  4. E parlando di prestazioni, spesso otterrai l'accelerazione hardware gratuitamente, poiché la maggior parte delle moderne librerie 2D (come la tela di HTML5, credo) scaricherà il lavoro di rendering sugli acceleratori grafici.

L'unico svantaggio del pixel-painting è l'accuratezza finita della soluzione. Ma questo è sintonizzabile semplicemente eseguendo il rendering su tele più grandi o più piccole a seconda della situazione. Si noti inoltre che l' anti-aliasing nel codice di rendering 2D (spesso attivato per impostazione predefinita) produrrà una precisione a livello di pixel migliore. Quindi, ad esempio, il rendering di una figura 100x100 in una tela delle stesse dimensioni dovrebbe, credo, fornire una precisione dell'ordine di 1 / (100 x 100 x 255) = 0,000039% ... che è probabilmente "abbastanza buono" per tutti tranne i problemi più impegnativi.

<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);

Questa soluzione non tiene conto dell'esecuzione di calcoli matematici con le aree dei cerchi. Non coglie il punto della domanda dei PO. Molto spesso la geometria del rendering è solo metà della battaglia quando si tratta di forme geometriche
Steve
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.