Как рассчитать площадь двухмерного многоугольника?

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

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

Термин «площадь поверхности» немного вводит в заблуждение. Кажется, вам нужна только (обычная) область. В 3D площадь поверхности - это площадь внешней поверхности, поэтому естественным двухмерным обобщением этой концепции будет длина периметра многоугольника, что явно не то, что вы ищете.

batty 25.02.2010 07:59

область определения (многоугольник): return abs (numpy.cross (polygon, numpy.roll (polygon, -1, 0)). sum () / 2)

iouvxz 20.11.2017 09:52
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
81
2
73 436
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

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

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

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

Richard 17.11.2012 23:44

@Richard: Вот почему квалификация около 180 градусов. Если вы отрежете треугольник за пределами многоугольника, вы получите слишком много градусов.

Loren Pechtel 19.11.2012 00:28

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

Richard 19.11.2012 02:09

@Richard: На вашем многоугольнике у вас есть угол каждого соединения. Если соответствующий треугольник будет лежать за пределами многоугольника, угол между двумя сегментами будет больше 180 градусов.

Loren Pechtel 19.11.2012 23:08

Вы имеете в виду, что внутренний угол двух смежных сегментов кромки будет больше 180 градусов.

Richard 20.11.2012 00:36

Ага - я смотрю на углы, если смотреть изнутри многоугольника. Если предполагаемый треугольник на самом деле лежит за пределами многоугольника, у вас будут три угла больше 180, если смотреть с этой точки обзора. Тем не менее, достаточно протестировать первое.

Loren Pechtel 21.11.2012 01:17

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

  1. Задайте базовую точку (самую выпуклую точку). Это будет ваша точка поворота треугольников.
  2. Вычислите самую левую точку (произвольную), кроме вашей базовой точки.
  3. Вычислите 2-ю крайнюю левую точку, чтобы завершить треугольник.
  4. Сохраните эту триангулированную область.
  5. Сдвигайте на одну точку вправо на каждой итерации.
  6. Суммируйте триангулированные площади

Убедитесь, что вы отрицаете площадь треугольника, если следующая точка движется «назад».

recursive 17.01.2009 23:24

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

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

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

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

Ответ принят как подходящий

Вот стандартный метод, 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

Стоит упомянуть, почему этот алгоритм работает: это приложение теоремы Грина для функций -y и x; точно так же, как планиметр. Более конкретно: формула, приведенная выше = целочисленный_пермиитер (-y dx + x dy) = интегральная_площадь ((- (- dy) / dy + dx / dx) dydyx = 2 Площадь

David Lehavi 17.01.2009 09:44

Ссылка в посте мертвая. У кого-нибудь есть другая?

Yakov 11.07.2011 16:42

Связанное обсуждение в списке рассылки [email protected] мне недоступно. Скопировал сообщение из Google Cache: gist.github.com/1200393

Andrew Андрей Листочкин 07.09.2011 16:10

Вот еще одна ссылка для объяснения. mathopenref.com/coordpolygonarea.html

imsc 17.02.2012 14:09

имеет значение порядок баллов? Я имею в виду, должно ли это быть против часовой стрелки или по часовой стрелке или не имеет значения?

Sibbs Gambling 09.11.2013 12:34

@ perfectionm1ng переключение направлений перевернуло бы знак в сумме, но abs() убирает знак.

Darius Bacon 19.11.2013 13:38

Ограничения: этот метод даст неправильный ответ для самопересекающихся многоугольников, когда одна сторона пересекает другую, как показано справа. Однако он будет работать правильно для треугольников, правильных и неправильных многоугольников, выпуклых или вогнутых многоугольников. (mathopenref.com/coordpolygonarea.html)

OneWorld 12.10.2016 10:01

«Неправильный» ответ - это вопрос определения. Например, если вы таким образом вычислили площадь пентаграммы, она не учитывала бы площадь центрального пятиугольника. Но если вы визуализировали заполненную пентаграмму, например, SVG, он также оставил бы этот пятиугольник незаполненным! Я согласен с тем, что стоит упомянуть, что этот ответ дает абсолютное значение области подписанный.

Darius Bacon 15.10.2016 06:35

Это также известно в Википедии как Формула шнурков.

PHPirate 25.06.2018 15:37

Я начал писать этот вопрос, но потом понял, что ответ на него уже был в ответе Дария. Надеюсь, мой комментарий может помочь кому-то еще, у кого есть этот вопрос; при наличии всего 4 точек вогнутый многоугольник неоднозначен; рассмотрим точки (0,0), (-1,-1),(1,0), and (0,1); область зависит от того, какие 2 точки подключены к (0,0) посередине. Дариус ответил на это «неявным переходом от последней вершины к первой», потому что порядок говорит вам, с какими двумя другими точками (0,0) примыкает.

Nathan 01.02.2019 17:57

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

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

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

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

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

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

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

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;
}

Перекрестное произведение - это классика.

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

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 не четное.

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

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

Обновлено: «Площадь треугольников и многоугольников 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;

Я не могу представить, что второй фрагмент кода будет работать. Совершенно очевидно, что чем дальше многоугольник находится по оси X, тем больше будет его площадь.

Cygon 29.04.2012 13:19

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

chmike 14.05.2012 13:12

Извините, но я не думаю, что это правильно. Достаточно взглянуть на цикл, чтобы увидеть, что он не может работать. Вот пример программы, которая демонстрирует, что результат второго алгоритма полностью меняется в зависимости от перемещения многоугольника по оси X: pastebin.com/Mb8uQpz5

Cygon 15.05.2012 18:58

Я проверил образец программы, используя ваши значения, и не вижу разницы в площади. Я вижу разницу между вашим кодом и вторым алгоритмом: условие цикла for i <= N, а не i <n. Это может объяснить, почему вы не получаете ожидаемого результата.

chmike 15.05.2012 19:45

Что вы упустили из виду, так это то, что в сложении всегда есть отрицательные члены из-за вычитания y. Рассмотрим любую двумерную многоугольную форму и сравните значения y последовательных вершин. Вы увидите, что какое-то вычитание даст отрицательное значение, а какое-то положительное.

chmike 15.05.2012 19:52

Действительно, этот последний абзац - это то, о чем я не мог осмыслить! С i <= N это работает. Спасибо за терпение, беру все обратно :)

Cygon 15.05.2012 20:07

Без проблем. Я рада быть полезной. В этом цель StackExchange. Кроме того, вы могли найти ошибку или неправильный ответ, и в этом случае вы были бы мне полезны. :)

chmike 16.05.2012 15:45

Кстати, область, возвращаемая алгоритмом, является «подписанной» (отрицательной или положительной в зависимости от порядка точек), поэтому, если вы хотите всегда положительную область, просто используйте абсолютное значение.

NightElfik 06.11.2014 09:57

Первый алгоритм опасен. После первой итерации вы можете получить доступ за массивом, если есть только 4 точки.

ploth 19.09.2018 13:34

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

ДАННЫЙ: многоугольник ВСЕГДА может быть составлен из n-2 треугольников, которые не перекрываются (n = количество точек ИЛИ сторон). 1 треугольник = 3-сторонний многоугольник = 1 треугольник; 1 квадрат = 4-сторонний многоугольник = 2 треугольника; и т. д. до тошноты QED

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

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

  1. получившийся треугольник полностью находится внутри исходного многоугольника
  2. получившийся треугольник полностью выходит за пределы исходного многоугольника
  3. получившийся треугольник частично содержится в исходном многоугольнике

нас интересуют только случаи, которые относятся к первому варианту (полностью ограничены).

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

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

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

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

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

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);
}    

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

Mark Taylor 05.10.2012 01:05

Это пример на c, а не на python. Не лучше, но приятно иметь его на разных языках

underdoeg 27.08.2015 17:11

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

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

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

Окончательное суммирование более эффективно, поскольку требует умножения только n вместо 2n.

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

Спасибо за версию NumPy.

physicsmichael 11.06.2014 21:03

Реализация Формула шнурков может быть выполнена в 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

Избежание цикла делает эту функцию примерно в 50 раз быстрее, чем 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

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

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;
}

I'm going to give a few simple functions for calculating area of 2d polygon. This works for both convex and concave polygons. we simply divide the polygon into many sub-triangles.

//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;
}
cp принимает два аргумента, а вы вызываете его с помощью одного.
user9315861 09.07.2018 20:03

Код Python

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

С пандами

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

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