Нехай А_1(x_1, y_1), А_2(x_2, y_2), ..., А_n(x_n, y_n) — вершини простого (без самоперетинів) многокутника, задані в порядку його обходу за годинниковою стрілкою або проти неї. Тоді площа многокутника обчислюється за формулою трапецій:
де А_{n+1}(x_{n+1}, y_{n+1} = А_1(x_1, y_1).
Кожен доданок суми являє собою орієнтовану площу трапеції, обмеженої стороною A_iA_{i+1}, віссю абсцис та вертикальними прямими x = x_i і x = x_{i+1}. Основи трапеції дорівнюють y_i та y_{i+1}, висота дорівнює x_{i+1} - x_i. При y_i + y_{i+1} > 0 площа трапеції додатна, якщо x_{i+1} > x_i, і від'ємна, якщо x_{i+1} < x_i.
При підсумовуванні по всіх сторонах площі ділянок, що лежать поза многокутником, входять до суми двічі з протилежними знаками і взаємно знищуються, тому залишається тільки площа самого многокутника. Знак суми залежить від напрямку обходу: при обході за годинниковою стрілкою вона додатна, проти годинникової стрілки — від'ємна. Оскільки напрямок обходу заздалегідь невідомий, результат береться за модулем.
При обході A \to B \to C \to D \to E \to A три верхні сторони проходяться зліва направо, тому трапеції під ними входять до суми з плюсом і разом закривають усе від ламаної до осі абсцис. Дві нижні сторони проходяться справа наліво, і трапеції під ними віднімаються: вони прибирають заштриховану частину під ламаною . Залишається многокутник:
Площу многокутника можна також знайти за формулою Сюрвейора (Surveyor), відомою як формула Гаусса або формула шнурування:
де А_{n+1}(x_{n+1}, y_{n+1}) = А_1(x_1, y_1).
Нехай O(0, 0) — центр координат. Тоді площа многокутника дорівнює сумі орієнтованих площ трикутників OA_1A_2, OA_2A_3, OA_3A_4, ..., OA_nA_1. Якщо вершини трикутника OA_iA_{i+1} перелічені проти годинникової стрілки, його площа вважається додатною, якщо за годинниковою стрілкою — від'ємною.
Многокутник A_1A_2A_3A_4A_5 обходиться проти годинникової стрілки, точка лежить поза ним. Три найдальші від сторони дають трикутники, орієнтовані проти годинникової стрілки: їхні площі додатні, і разом вони закривають усе від точки до ламаної A_1A_2A_3A_4. Дві найближчі сторони дають трикутники, орієнтовані за годинниковою стрілкою: вони віднімаються і прибирають заштриховану область між та ламаною A_4A_5A_1. Залишається многокутник:
Орієнтована площа трикутника OA_iA_{i+1} дорівнює половині псевдоскалярного добутку векторів OA_i та OA_{i+1}, тобто половині визначника другого порядку з рядками (x_i, y_i) і (x_{i+1}, y_{i+1}):
Реалізація алгоритму
Координати вершин многокутника зберігаємо в масивах та :
-та вершина має координати (x[i], y[i])
Розмір масивів на одиницю більший за максимальну кількість вершин, оскільки в позицію додатково записується копія першої вершини.
#define MAX 1002
int x[MAX], y[MAX];Функція findArea обчислює площу многокутника за формулою трапецій.
double findArea(int *x, int *y)
{
double s = 0;Щоб замкнути многокутник, перша вершина копіюється в позицію : тоді сторона, що з'єднує останню вершину з першою, обробляється в загальному циклі без окремої перевірки.
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;Знак суми залежить від напрямку обходу, тому функція повертає її модуль.
return (s < 0) ? -s : s;
}Основна частина програми. Читаємо вхідні дані.
scanf("%d",&n);
for(i = 0; i < n; i++)
scanf("%d %d",&x[i],&y[i]);Обчислюємо та виводимо площу многокутника.
printf("%.3lf\n",findArea(x,y));Реалізація алгоритму – формула Сюрвейора
Функція findArea обчислює площу многокутника за формулою Сюрвейора. Координати вершин передаються у векторах та за посиланням: -та вершина має координати (x[i], y[i]).
double findArea(vector<int> &x, vector<int> &y)
{
double s = 0;Щоб замкнути многокутник, перша вершина дописується в кінець обох векторів: тоді сторона, що з'єднує останню вершину з першою, обробляється в загальному циклі без окремої перевірки.
x.push_back(x[0]); y.push_back(y[0]);Після цього вектори містять n + 1 елемент, тому цикл виконується для від до x.size() - 2. На кожній ітерації до суми додається подвоєна орієнтована площа трикутника OA_iA_{i+1}.
for (int i = 0; i < x.size() - 1; i++)
s += y[i+1] * x[i] - y[i] * x[i+1];Знак суми залежить від напрямку обходу, тому функція повертає половину її модуля.
return fabs(s) / 2.0;
}Оголошуємо вектори координат.
vector<int> x, y;Основна частина програми. Читаємо кількість вершин та їхні координати, додаючи кожну вершину в кінець векторів.
scanf("%d",&n);
for(i = 0; i < n; i++)
{
scanf("%d %d",&a,&b);
x.push_back(a);
y.push_back(b);
}Обчислюємо та виводимо площу многокутника.
printf("%.3lf\n",findArea(x,y));Реалізація алгоритму – класи
#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;
}