Siano А_1(x_1, y_1), А_2(x_2, y_2), ..., А_n(x_n, y_n) — i vertici di un poligono semplice (senza autointersezioni), dati nell'ordine del suo percorso in senso orario o antiorario. Allora l'area del poligono si calcola con la formula dei trapezi:
dove А_{n+1}(x_{n+1}, y_{n+1} = А_1(x_1, y_1).
Ogni termine della somma rappresenta l'area orientata del trapezio delimitato dal lato A_iA_{i+1}, dall'asse delle ascisse e dalle rette verticali x = x_i e x = x_{i+1}. Le basi del trapezio sono y_i e y_{i+1}, l'altezza è x_{i+1} - x_i. Quando y_i + y_{i+1} > 0, l'area del trapezio è positiva se x_{i+1} > x_i, e negativa se x_{i+1} < x_i.
Sommando su tutti i lati, le aree delle zone esterne al poligono entrano nella somma due volte con segni opposti e si annullano a vicenda, per cui rimane solo l'area del poligono stesso. Il segno della somma dipende dalla direzione del percorso: quando il percorso è in senso orario essa è positiva, in senso antiorario è negativa. Poiché la direzione del percorso non è nota in anticipo, il risultato viene preso in valore assoluto.
Nel percorso A \to B \to C \to D \to E \to A i tre lati superiori vengono percorsi da sinistra a destra, quindi i trapezi sottostanti entrano nella somma con il segno più e insieme coprono tutto lo spazio dalla spezzata fino all'asse delle ascisse. I due lati inferiori vengono percorsi da destra a sinistra, e i trapezi sottostanti vengono sottratti: essi rimuovono la parte tratteggiata sotto la spezzata . Resta il poligono:
L'area del poligono può essere calcolata anche con la formula di Surveyor (Surveyor), nota come formula di Gauss o formula del laccio (shoelace formula):
dove А_{n+1}(x_{n+1}, y_{n+1}) = А_1(x_1, y_1).
Sia O(0, 0) — l'origine delle coordinate. Allora l'area del poligono è uguale alla somma delle aree orientate dei triangoli OA_1A_2, OA_2A_3, OA_3A_4, ..., OA_nA_1. Se i vertici del triangolo OA_iA_{i+1} sono elencati in senso antiorario, la sua area è considerata positiva; se in senso orario — negativa.
Il poligono A_1A_2A_3A_4A_5 viene percorso in senso antiorario, il punto si trova all'esterno di esso. I tre lati più lontani da danno triangoli orientati in senso antiorario: le loro aree sono positive, e insieme coprono tutto lo spazio dal punto fino alla spezzata A_1A_2A_3A_4. I due lati più vicini danno triangoli orientati in senso orario: essi vengono sottratti e rimuovono l'area tratteggiata tra e la spezzata A_4A_5A_1. Resta il poligono:
L'area orientata del triangolo OA_iA_{i+1} è uguale alla metà del prodotto pseudoscalare dei vettori OA_i e OA_{i+1}, cioè alla metà del determinante del secondo ordine con righe (x_i, y_i) e (x_{i+1}, y_{i+1}):
Implementazione dell'algoritmo
Le coordinate dei vertici del poligono vengono memorizzate negli array e :
l'-esimo vertice ha coordinate (x[i], y[i])
La dimensione degli array è maggiore di un'unità rispetto al numero massimo di vertici, poiché nella posizione viene scritta in aggiunta una copia del primo vertice.
#define MAX 1002
int x[MAX], y[MAX];La funzione findArea calcola l'area del poligono utilizzando la formula dei trapezi.
double findArea(int *x, int *y)
{
double s = 0;Per chiudere il poligono, il primo vertice viene copiato nella posizione : in questo modo il lato che collega l'ultimo vertice al primo viene elaborato nel ciclo generale senza bisogno di un controllo separato.
x[n] = x[0]; y[n] = y[0];
for(int i = 0; i < n; i++)
s += (y[i+1] + y[i]) * (x[i+1] - x[i]) / 2.0;Il segno della somma dipende dalla direzione del percorso, quindi la funzione restituisce il suo valore assoluto.
return (s < 0) ? -s : s;
}Parte principale del programma. Leggiamo i dati di input.
scanf("%d",&n);
for(i = 0; i < n; i++)
scanf("%d %d",&x[i],&y[i]);Calcoliamo e stampiamo l'area del poligono.
printf("%.3lf\n",findArea(x,y));Implementazione dell'algoritmo – formula di Surveyor
La funzione findArea calcola l'area del poligono utilizzando la formula di Surveyor. Le coordinate dei vertici vengono passate nei vettori e per riferimento: l'-esimo vertice ha coordinate (x[i], y[i]).
double findArea(vector<int> &x, vector<int> &y)
{
double s = 0;Per chiudere il poligono, il primo vertice viene aggiunto alla fine di entrambi i vettori: in questo modo il lato che collega l'ultimo vertice al primo viene elaborato nel ciclo generale senza bisogno di un controllo separato.
x.push_back(x[0]); y.push_back(y[0]);Dopo di che i vettori contengono n + 1 elementi, quindi il ciclo viene eseguito per da a x.size() - 2. Ad ogni iterazione viene aggiunta alla somma l'area orientata raddoppiata del triangolo OA_iA_{i+1}.
for (int i = 0; i < x.size() - 1; i++)
s += y[i+1] * x[i] - y[i] * x[i+1];Il segno della somma dipende dalla direzione del percorso, quindi la funzione restituisce la metà del suo valore assoluto.
return fabs(s) / 2.0;
}Dichiariamo i vettori delle coordinate.
vector<int> x, y;Parte principale del programma. Leggiamo il numero di vertici e le loro coordinate, aggiungendo ogni vertice alla fine dei vettori.
scanf("%d",&n);
for(i = 0; i < n; i++)
{
scanf("%d %d",&a,&b);
x.push_back(a);
y.push_back(b);
}Calcoliamo e stampiamo l'area del poligono.
printf("%.3lf\n",findArea(x,y));Implementazione dell'algoritmo – classi
#include <stdio.h>
class Point
{
private:
double x, y;
public:
Point(double x = 0, double y = 0) : x(x), y(y) {};
double GetX()
{
return x;
}
double GetY()
{
return y;
}
// cross product
double operator* (const Point &p)
{
return this->x * p.y - this->y * p.x;
}
};
class Shape
{
protected:
Point *p;
int size;
public:
Shape(int size = 0) : size(size)
{
p = new Point[size+1];
}
~Shape()
{
delete[] p;
}
};
class Polygon : public Shape
{
public:
Polygon(int n = 0) : Shape(n) {};
void ReadPoints(void)
{
double x, y;
for(int i = 0; i < size; i++)
{
scanf("%lf %lf",&x,&y);
p[i] = Point(x,y);
}
p[size] = p[0];
}
double Area(void)
{
double s = 0;
for(int i = 0; i < size; i++)
s += p[i] * p[i+1];
return (s < 0) ? -s/2 : s/2;
}
};
int n;
int main(void)
{
scanf("%d",&n);
Polygon p(n);
p.ReadPoints();
printf("%.3lf\n",p.Area());
return 0;
}