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

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

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

57
задан Jason Z 16 янв. '09 в 21:18
источник поделиться

16 ответов

Вот стандартный метод, 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; точно так, как работает planimeter. Более конкретно:

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

75
ответ дан Darius Bacon 16 янв. '09 в 21:39
источник поделиться

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

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

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;
13
ответ дан chmike 04 апр. '09 в 19:38
источник поделиться

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

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
8
ответ дан unutbu 09 нояб. '13 в 14:48
источник поделиться

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

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

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

4
ответ дан mbeckish 16 янв. '09 в 21:34
источник поделиться

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

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

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

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

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

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

4
ответ дан MSN 16 янв. '09 в 21:40
источник поделиться

Чтобы вычислить площадь многоугольника

http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=geometry1#polygon_area

int cross(vct a,vct b,vct c)
{
    vct ab,bc;
    ab=b-a;
    bc=c-b;
    return ab.x*bc.y-ab.y*bc.x;
}    
double area(vct p[],int n)
{ 
    int ar=0;
    for(i=1;i+1<n;i++)
    {
        vct a=p[i]-p[0];
        vct b=p[i+1]-p[0];
        area+=cross(a,b);
    }
    return abs(area/2.0);
}    
3
ответ дан Steve 04 окт. '12 в 18:05
источник поделиться

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

2
ответ дан duffymo 16 янв. '09 в 21:33
источник поделиться

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

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. важная проблема заключается в том, считаете ли вы район плоской или изогнутой. в общем, "малые" области, где точки до нескольких километров друг от друга, не вызовут существенной ошибки, если рассматривать плоские и не выпуклые.

1
ответ дан user836725 21 авг. '11 в 18:06
источник поделиться

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

1
ответ дан MattK 16 янв. '09 в 21:24
источник поделиться
  • Задайте базовую точку (наиболее выпуклую точку). Это будет ваша точка поворота треугольников.
  • Рассчитайте самую левую точку (произвольную), отличную от вашей базовой точки.
  • Рассчитайте вторую-самую левую точку, чтобы завершить свой треугольник.
  • Сохраните эту триангулированную область.
  • Сдвиньте одну точку вправо на каждую итерацию.
  • Суммируйте триангулированные области
1
ответ дан Joe Phillips 16 янв. '09 в 21:25
источник поделиться

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

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;
}
1
ответ дан David Hanak 16 янв. '09 в 22:34
источник поделиться

Реализация Формула 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

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

0
ответ дан Mahdi 20 июня '15 в 9:07
источник поделиться

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;
}
0
ответ дан Joseph 03 дек. '15 в 0:27
источник поделиться

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

//don't forget to include cmath for abs function
struct Point{
  double x;
  double y;
}

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;
}
0
ответ дан abe312 03 апр. '17 в 1:47
источник поделиться

Код 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
0
ответ дан firelynx 29 сент. '17 в 9:29
источник поделиться

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

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

0
ответ дан Loren Pechtel 16 янв. '09 в 21:23
источник поделиться

Другие вопросы по меткам