Как вычислить площадь 2-го многоугольника?

Предполагая, что ряд точек в 2d-пространстве не самопересекается, что является эффективным методом определения области результирующего многоугольника?

Как побочная заметка, это не домашнее задание, и я не ищу код. Я ищу описание, которое я могу использовать для реализации моего собственного метода. У меня есть мои идеи о том, чтобы вывести последовательность треугольников из списка точек, но я знаю, что есть куча краевых случаев относительно выпуклых и вогнутых полигонов, которые я, вероятно, не поймаю.

Ответ 1

Вот стандартный метод, AFAIK. В основном суммируйте поперечные произведения вокруг каждой вершины. Гораздо проще, чем триангуляция.

Код Python, заданный многоугольник, представленный как список (x, y) вершинных координат, неявно обертывающий от последней вершины к первому:

def area(p):
    return 0.5 * abs(sum(x0*y1 - x1*y0
                         for ((x0, y0), (x1, y1)) in segments(p)))

def segments(p):
    return zip(p, p[1:] + [p[0]])

Дэвид Лехави комментирует: стоит упомянуть, почему работает этот алгоритм: это применение теоремы Грина для функций -y и x; точно так, как работает плоскомер. Более конкретно:

Формула выше =
integral_over_perimeter(-y dx + x dy) =
integral_over_area((-(-dy)/dy+dx/dx) dy dx) =
2 Area

Ответ 2

Перекрестный продукт является классическим.

Если у вас есть миллион таких вычислений, попробуйте следующую оптимизированную версию, для которой требуется меньше половины умножений:

area = 0;
for( i = 0; i < N; i += 2 )
   area += x[i+1]*(y[i+2]-y[i]) + y[i+1]*(x[i]-x[i+2]);
area /= 2;

Я использую индекс массива для ясности. Эффективно использовать указатели. Хотя хорошие компиляторы сделают это за вас.

Полигон считается "закрытым", что означает, что вы копируете первую точку как точку с индексом N. Также предполагается, что многоугольник имеет четное число точек. Добавим дополнительную копию первой точки, если N не равно.

Алгоритм получается путем разворачивания и объединения двух последовательных итераций классического алгоритма кросс-произведения.

Я не уверен, как сравниваются два алгоритма относительно числовой точности. Мое впечатление, что вышеупомянутый алгоритм лучше классического, потому что умножение стремится восстановить потерю точности вычитания. При ограничении использования float, как и в случае с графическим процессором, это может иметь существенное значение.

EDIT: "Область треугольников и многоугольников 2D и 3D" описывает еще более эффективный метод

// "close" polygon
x[N] = x[0];
x[N+1] = x[1];
y[N] = y[0];
y[N+1] = y[1];

// compute area
area = 0;
for( size_t i = 1; i <= N; ++i )
  area += x[i]*( y[i+1] - y[i-1] );
area /= 2;

Ответ 3

Эта страница показывает, что формула

enter image description here

можно упростить до:

enter image description here

Если вы выписываете несколько терминов и группируете их в соответствии с общими факторами xi, то равенство нетрудно увидеть.

Последнее суммирование более эффективно, так как для n требуется только умножение n.

def area(x, y):
    return abs(sum(x[i] * (y[i + 1] - y[i - 1]) for i in xrange(-1, len(x) - 1))) / 2.0

Я изучил это упрощение от Джо Кингтона, здесь.


Если у вас есть NumPy, эта версия работает быстрее (для всех, но очень малых массивов):

def area_np(x, y):        
    x = np.asanyarray(x)
    y = np.asanyarray(y)
    n = len(x)
    shift_up = np.arange(-n+1, 1)
    shift_down = np.arange(-1, n-1)    
    return (x * (y.take(shift_up) - y.take(shift_down))).sum() / 2.0

Ответ 4

Множество точек без каких-либо других ограничений не обязательно однозначно определяет многоугольник.

Итак, сначала вам нужно решить, какой полигон построить из этих точек - возможно, выпуклый корпус? http://en.wikipedia.org/wiki/Convex_hull

Затем триангулируем и вычисляем область. http://www.mathopenref.com/polygonirregulararea.html

Ответ 5

Чтобы расширить области триангуляций и треугольников суммирования, они работают, если у вас есть выпуклый многоугольник ИЛИ вы случайно выбрали точку, которая не создает линии для каждой другой точки, пересекающей многоугольник.

Для общего непересекающегося многоугольника вам нужно суммировать поперечное произведение векторов (контрольная точка, точка a), (контрольная точка, точка b), где a и b "следуют" друг к другу.

Предполагая, что у вас есть список точек, которые определяют многоугольник в порядке (порядок, когда точки я и я + 1 образуют линию многоугольника):

Сумма (кросс-произведение ((точка 0, точка i), (точка 0, точка я + 1)) для я = 1 до n-1.

Возьмите величину этого кросс-продукта, и у вас есть площадь поверхности.

Это будет обрабатывать вогнутые многоугольники, не беспокоясь о выборе хорошей контрольной точки; любые три точки, которые генерируют треугольник, который не находится внутри многоугольника, будут иметь поперечное произведение, которое указывает в противоположном направлении любого треугольника, который находится внутри многоугольника, поэтому области правильно суммируются.

Ответ 7

Или сделать контурный интеграл. Теорема Стокса позволяет выразить интеграл области как контурный интеграл. Маленькая гауссова квадратура и Боб твой дядя.

Ответ 9

  • Задайте базовую точку (наиболее выпуклую точку). Это будет ваша точка поворота треугольников.
  • Рассчитайте самую левую точку (произвольную), отличную от вашей базовой точки.
  • Рассчитайте вторую-самую левую точку, чтобы завершить свой треугольник.
  • Сохраните эту триангулированную область.
  • Сдвиньте одну точку вправо на каждую итерацию.
  • Суммируйте триангулированные области

Ответ 10

Лучше суммирования треугольников суммирует трапеции в декартовом пространстве:

area = 0;
for (i = 0; i < n; i++) {
  i1 = (i + 1) % n;
  area += (vertex[i].y + vertex[i1].y) * (vertex[i1].x - vertex[i].x) / 2.0;
}

Ответ 11

независимое от языка решение:

GIVEN: многоугольник может ВСЕГДА состоять из n-2 треугольников, которые не перекрываются (n = количество точек OR сторон). 1 треугольник = трехгранный многоугольник = 1 треугольник; 1 квадрат = 4-сторонний многоугольник = 2 треугольника; и т.д. ad nauseam QED

поэтому многоугольник может быть уменьшен путем "измельчения" треугольников, а общая площадь будет суммой площадей этих треугольников. попробуйте с листом бумаги и ножницами, лучше всего, если вы представите процесс, прежде чем следовать.

если вы берете любые 3 последовательных точки в пути многоугольников и создаете треугольник с этими точками, у вас будет один и только один из трех возможных сценариев:

  • полученный треугольник полностью внутри оригинального многоугольника
  • полученный треугольник полностью вне оригинального многоугольника
  • полученный треугольник частично содержится в исходном многоугольнике

нас интересуют только случаи, которые попадают в первый вариант (полностью содержащийся).

каждый раз, когда мы находим один из них, мы прерываем его, вычисляем его площадь (легко peasy, не будем здесь объяснять формулу) и создаем новый многоугольник с одной меньшей стороной (эквивалент многоугольника с отрубленным треугольником). пока мы не оставим только один треугольник.

как реализовать это программно:

создать массив (последовательных) точек, которые представляют путь ВОКРУГ многоугольника. начните в точке 0. запустите массив, создавая треугольники (по одному за раз) из точек x, x + 1 и x + 2. преобразуйте каждый треугольник из формы в область и пересечь его с областью, созданной из многоугольника. Если полученное пересечение идентично исходному треугольнику, то указанный треугольник полностью содержится в многоугольнике и может быть отрублен. удалите x + 1 из массива и начните снова с x = 0. в противном случае (если треугольник находится вне [частично или полностью] многоугольника), перейдите к следующей точке x + 1 в массиве.

дополнительно, если вы хотите интегрироваться с отображением и начинать с геоинтеграции, вы должны преобразовать из геотомов в экранные точки FIRST. это требует решения моделирования и формулы для формы земли (хотя мы склонны думать о Земле как о шаре, это на самом деле нерегулярная яйцевидная (яйцо) с вмятинами). существует много моделей, для получения дополнительной информации wiki. важная проблема заключается в том, считаете ли вы район плоской или изогнутой. в общем, "малые" области, где точки до нескольких километров друг от друга, не вызовут существенной ошибки, если рассматривать плоские и не выпуклые.

Ответ 12

Реализация Формула Shoelace может быть выполнена в Numpy. Предположим, что эти вершины:

import numpy as np
x = np.arange(0,1,0.001)
y = np.sqrt(1-x**2)

Мы можем определить следующую функцию для поиска области:

def PolyArea(x,y):
    return 0.5*np.abs(np.dot(x,np.roll(y,1))-np.dot(y,np.roll(x,1)))

И получение результатов:

print PolyArea(x,y)
# 0.26353377782163534

Избегающий цикл делает эту функцию ~ 50X быстрее, чем PolygonArea:

%timeit PolyArea(x,y)
# 10000 loops, best of 3: 42 µs per loop
%timeit PolygonArea(zip(x,y))
# 100 loops, best of 3: 2.09 ms per loop

Примечание. Я написал этот ответ для другого вопроса , я просто упомянул об этом здесь, чтобы иметь полный список решений.

Ответ 13

Моя склонность состояла в том, чтобы просто нарезать треугольники. Я не вижу, как что-то еще может избежать ужасно волосатого.

Возьмите три последовательные точки, которые составляют многоугольник. Убедитесь, что угол меньше 180. Теперь у вас есть новый треугольник, который не представляет проблемы для вычисления, удалите среднюю точку из списка полигонов точек. Повторяйте пока у вас осталось всего три очка.

Ответ 14

C способ сделать это:

float areaForPoly(const int numVerts, const Point *verts)
{
    Point v2;
    float area = 0.0f;

    for (int i = 0; i<numVerts; i++){
        v2 = verts[(i + 1) % numVerts];
        area += verts[i].x*v2.y - verts[i].y*v2.x;
    }

    return area / 2.0f;
}

Ответ 15

Я собираюсь дать несколько простых функций для вычисления области многоугольника 2d. Это работает как для выпуклых, так и для вогнутых многоугольников. мы просто делим многоугольник на многие подтреугольники.

//don't forget to include cmath for abs function
struct Point{
  double x;
  double y;
}
// cross_product
double cp(Point a, Point b){ //returns cross product
  return a.x*b.y-a.y*b.x;
}

double area(Point * vertices, int n){  //n is number of sides
  double sum=0.0;
  for(i=0; i<n; i++){
    sum+=cp(vertices[i], vertices[(i+1)%n]); //%n is for last triangle
  }
  return abs(sum)/2.0;
}

Ответ 16

Код Python

Как описано здесь: http://www.wikihow.com/Calculate-the-Area-of-a-Polygon

С pandas

import pandas as pd

df = pd.DataFrame({'x': [10, 20, 20, 30, 20, 10, 0], 'y': [-10, -10, -10, 0, 10, 30, 20]})
df = df.append(df.loc[0])

first_product = (df['x'].shift(1) * df['y']).fillna(0).sum()
second_product = (df['y'].shift(1) * df['x']).fillna(0).sum()

(first_product - second_product) / 2
600