Come calcolare l'area di una forma irregolare?


17

Ho un oggetto room definito da una raccolta di segmenti di linea ciclica per i quali devo calcolare l'area. Le classi possono essere descritte come segue (in pseudo-codice):

class Point {
    float x; 
    float y;
    ...
    float distanceFrom(Point p);
}

class Segment {
    Point start;
    Point end;
    ...
    float length();
}

class Room {
    List<Segment> walls;
    ...
    float area();
}

Le pareti di una stanza non possono mai intersecarsi da nessuna parte, ma ai punti finali dei segmenti e anche eventuali "circuiti secondari" creati verranno separati in una nuova stanza. Non è necessario che la soluzione sia perfettamente accurata (il margine di errore del 10% è accettabile) e inoltre non viene calcolato molto spesso (<1 / s).


7
Avrebbe più senso Roomcontenere un elenco di Points, quindi ottenere i segmenti collegando ogni punto insieme e quindi ricircolarlo. Altrimenti, con la tua configurazione attuale, è molto a est ottenere valori errati (ad es. Stanza non chiusa, stanza con muro in mezzo, ecc.). Questa sarebbe l'opzione migliore.
MCMastery,

Un'altra opzione è triangolare in alto la forma e calcolare le aree di ciascun triangolo. La parte difficile è la triangolazione. Fattibile, ma non sempre carino. La risposta ai lacci delle scarpe è ancora molto meglio.
Draco18s non si fida più di SE

@MCMastery Quella soluzione non funzionerà, poiché richiede che Rooms sia sempre completa, e potrebbe non essere il caso se il giocatore costruisce Roomi messaggi usando Segments. Inoltre, una funzione di stanza chiusa è facile da definire (basta scorrere le Segments e assicurarsi che creino una stanza).

Risposte:


31

Puoi usare la formula del laccio da scarpe di Gauss :

Devi prendere la coordinata x di ogni punto, moltiplicarli per la coordinata y del punto successivo, quindi sottrarre la coordinata y del punto corrente moltiplicata per la coordinata x del punto successivo dal risultato e aggiungerli all'area totale. Dopo aver eseguito questa operazione per ogni punto, dimezza l'area totale per ottenere l'area effettiva del poligono. Se il punto corrente è l'ultimo, il successivo è il primo.

A = 0

for (i = 0; i < points.length; i++) do

    A += points[i].x * points[(i + 1) % points.length].y - points[i].y * points[(i + 1) % points.length].x

end

A /= 2

2
L'ho sempre usato per calcolare il prodotto incrociato di due vettori mai saputo che si chiamava algoritmo per lacci delle scarpe
Sidar,

3
Si noti che questo può essere esteso per calcolare il volume di un oggetto 3D irregolare fatto di triangoli e può essere considerato un caso banale del teorema fondamentale del calcolo.
Dietrich Epp,

5
L'area qui è firmata. Passa attraverso i punti nell'altra direzione e la finale Aviene annullata. A seconda dell'obiettivo, A = |A|potrebbe essere necessario un. Con il prefisso negativo puoi trovare l'area su una ciambella irregolare usando l'elenco interno ed esterno di punti (uno nell'ordine opposto).
chux - Ripristina Monica il

6
Perché ovviamente Gauss o Euler hanno una formula per questo.
corsiKa

0

Potremmo anche usare un metodo Monte Carlo.

Disegna un rettangolo attorno alla forma arbitraria. Prendi una fonte PRNG distribuita uniformemente, ad es. mersenne twister, quindi ha legato l'output in base alle lunghezze X, Y del rettangolo utilizzando la funzione modulo. Conta il no. di punti casuali che atterrano nella tua forma. Dividi per la quantità totale di punti generati. Moltiplica quel quoziente per l'area del rettangolo. Con ogni iterazione convergerete nell'area vera. L'algoritmo è ridicolmente parallelizzabile e può essere utilizzato per calcolare "volumi" di forme dimensionali arbitrarie, purché sia ​​possibile determinare se una coordinata R ^ N rientra nel limite R ^ N della forma.

.

Qui qualcuno sta usando questo metodo trova area cerchia quindi lo usa per calcolare pi https://www.youtube.com/watch?v=VJTFfIqO4TU


2
-1: Non vuoi usare il modulo per metterlo nel range, vuoi usare una distribuzione uniforme o altra distribuzione, facendolo nel modo modulo ha ogni sorta di problemi statistici.
user1997744

12
Questo metodo potrebbe essere utile quando non abbiamo un semplice poligono, ma piuttosto una sorta di forma implicita il cui bordo è difficile da esprimere, come un frattale o una chiazza di metaball. Per il caso di un poligono come nella domanda, sembra che sarebbe inutilmente costoso.
DMGregory

Come ha sottolineato @DMGregory, non è quello che stavo cercando. Tuttavia, penso che meriti un +1 nel caso in cui qualcun altro ne abbia bisogno.

Questo è interessante ma il costo dei test di inclusione non sarebbe proibitivo? Ad esempio, se hai una forma sufficientemente complessa da giustificare questo approccio, i test di inclusione non sarebbero anche molto costosi, quindi non vorresti farne tonnellate? (assumendo poligoni)
Mattia,

Ok modulo è davvero problematico, ma è una soluzione semplice. Ciò che otteniamo veramente è casuale P = 1/2 bit 0/1, quindi otteniamo una distribuzione uniforme dei numeri, ad es. per 3 bit da 0 a 7. Se si fa rand% 5, se un numero casuale assume il valore 6 o 7, viene mappato su 1 o 2, aumentando in modo effettivo 1,2 frequenze rendendo la distribuzione non uniforme. Per evitare che sia necessario qualcosa come una macchina a stati che ruota la mappatura, ad es. 6,7 viene mappato su 1,2, quindi su 3,4, quindi su 5,0 e continua. Potremmo anche buttare via 6,7 ​​ogni volta che si presentano. Comunque è un problema di implementazione della libreria.
Dal

-1

Un altro approccio: non farlo.

Anziché:

while (Segments.Count > 3)
{
    Segment A = Segments[Segments.Count - 2];
    Segment B = Segments[Segments.Count - 1];
    Segment C = new Segment(B.End, A.Start);
    Triangle T = new Triangle(A, B, C);
    Segments[Segments.Count - 2] = C;
    Segments.RemoveAt(Segments.Count - 1);
    if (B is inside the new shape Segments)
        Area -= T.Area;
    else
        Area += T.Area;
}
Area += new Triangle(Segments[0], Segments[1], Segments[2]).Area;

Fondamentalmente, tagliare un triangolo. L'area di un triangolo è semplice e in tal modo abbiamo ridotto il conteggio dei segmenti del resto di uno. Ripeti finché non rimane un triangolo.


2
La formula dei lacci delle scarpe di Gauss è una scorciatoia per questo che dimezza o terzi il numero di calcoli. Risolvilo.
Pieter Geerkens,
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.