Площадь полигона: формула шнуровки
Урок выводит и реализует формулу шнуровки — способ найти площадь произвольного многоугольника, зная только координаты его вершин.
Формула шнуровки (формула Гаусса, shoelace) вычисляет площадь простого многоугольника как полусумму перекрёстных произведений координат соседних вершин.
Площадь региона — базовый показатель: плотность населения, доля леса, размер участка. Если регион задан полигоном, его площадь нельзя «измерить линейкой» — её считают по координатам. Формула шнуровки делает это для любого простого (несамопересекающегося) многоугольника: хоть треугольника, хoть контура страны с тысячей вершин.
Откуда «шнуровка»
Площадь равна половине модуля суммы $\sum (x_i y_{i+1} - x_{i+1} y_i)$ по всем рёбрам. Если выписать координаты столбиком и перемножать накрест — вниз-вправо со знаком плюс, вниз-влево со знаком минус, — линии перемножений напоминают шнуровку ботинка. Отсюда название.
$S = \frac{1}{2}\left|\sum_{i=0}^{n-1}\left(x_i\,y_{i+1} - x_{i+1}\,y_i\right)\right|$
Индекс $i+1$ берётся по кругу: после последней вершины снова идёт первая.
Реализация
def polygon_area(poly):
n = len(poly)
s = 0.0
for i in range(n):
x1, y1 = poly[i]
x2, y2 = poly[(i + 1) % n] # следующая, замыкая на первую
s += x1 * y2 - x2 * y1
return abs(s) / 2
# Прямоугольник 4 x 3
rect = [(0, 0), (4, 0), (4, 3), (0, 3)]
print(f"Прямоугольник: {polygon_area(rect)}")
# Треугольник с основанием 4 и высотой 3 -> площадь 6
tri = [(0, 0), (4, 0), (2, 3)]
print(f"Треугольник: {polygon_area(tri)}")
# L-образный полигон (площадь 12: квадрат 4x4 минус вырез 2x2)
L = [(0, 0), (4, 0), (4, 2), (2, 2), (2, 4), (0, 4)]
print(f"Фигура L: {polygon_area(L)}")
Вывод:
Прямоугольник: 12.0 Треугольник: 6.0 Фигура L: 12.0
Все три ответа совпадают с геометрической проверкой: $4 \times 3 = 12$, $\frac{1}{2}\cdot 4 \cdot 3 = 6$, а L — это квадрат $4\times4=16$ минус вырез $2\times2=4$, итого $12$.
Как работает под капотом
Каждое слагаемое $x_i y_{i+1} - x_{i+1} y_i$ — это удвоенная площадь треугольника, образованного началом координат и ребром $i \to i{+}1$. Суммируя по контуру, мы складываем эти треугольники со знаком: части полигона учитываются плюсом, «вычитаемые» части (как вырез) — минусом, и всё лишнее взаимно сокращается. Знак суммы (до взятия модуля) кодирует направление обхода: против часовой стрелки — плюс, по часовой — минус. Это используют, чтобы определить ориентацию контура. Важная оговорка: для географических координат в градусах формула даст «квадратные градусы» — бессмыслицу; сначала полигон проецируют в метры (UTM), и только там площадь получается в честных квадратных метрах.
Частые ошибки
- Не замкнуть контур. Оператор
(i + 1) % nобязателен, иначе потеряется последнее ребро. - Забыть модуль и делить на 2. Без модуля знак зависит от направления обхода; без деления получится удвоенная площадь.
- Считать площадь в градусах. Для Земли сперва проецируйте в метры — иначе число не имеет физического смысла.
Почему именно перекрёстное произведение
За формулой шнуровки стоит красивая геометрия, и понимание её спасает от механического заучивания. Величина $x_i y_{i+1} - x_{i+1} y_i$ — это векторное произведение двух радиус-векторов из начала координат к концам ребра, а оно равно удвоенной площади треугольника «начало координат — две вершины ребра», взятой со знаком. Обходя контур, мы как веером заметаем эти треугольники от точки отсчёта; те, что «лишние» (вне фигуры), при обходе заметаются в обратную сторону и входят с минусом, аккуратно вычитаясь. В итоге, где бы ни лежало начало координат — хоть внутри полигона, хоть далеко снаружи, — сумма всегда даёт верную площадь самой фигуры. Это свойство «независимости от точки отсчёта» — то, что делает формулу надёжной.
Из той же конструкции бесплатно следует тест ориентации. Положительная сумма (до модуля) означает обход против часовой стрелки, отрицательная — по часовой. В GeoJSON по соглашению внешнее кольцо полигона обходят против часовой, а внутренние «дырки» — по часовой; проверив знак, можно понять, контур это или вырез, и автоматически починить неправильно ориентированные данные. Для полигона с дырками площадь считают как площадь внешнего кольца минус площади внутренних — и знаки формулы делают это вычитание автоматически, если кольца ориентированы по соглашению.
Итог
- Формула шнуровки: $S = \frac{1}{2}\left|\sum (x_i y_{i+1} - x_{i+1} y_i)\right|$.
- Работает для любого простого многоугольника по координатам вершин.
- Знак суммы (до модуля) показывает направление обхода контура.
- На Земле площадь считают после проекции в метры, не в градусах.