Предполагая, что в 2-м пространстве есть ряд точек, которые не пересекаются друг с другом, каков эффективный метод определения площади получившегося многоугольника?
Кстати, это не домашнее задание, и я не ищу код. Я ищу описание, которое я могу использовать для реализации моего собственного метода. У меня есть идеи по извлечению последовательности треугольников из списка точек, но я знаю, что есть множество крайних случаев, касающихся выпуклых и вогнутых многоугольников, которые я, вероятно, не пойму.
область определения (многоугольник): return abs (numpy.cross (polygon, numpy.roll (polygon, -1, 0)). sum () / 2)





Я хотел бы просто начать вырезать треугольники. Я не понимаю, как еще что-то могло не быть ужасно волосатым.
Возьмите три последовательные точки, составляющие многоугольник. Убедитесь, что угол меньше 180. Теперь у вас есть новый треугольник, вычислить который не составит труда. Удалите среднюю точку из списка точек многоугольника. Повторяйте, пока у вас не останется только три точки.
Причина в том, что если ваши три последовательные точки определяют треугольник за пределами или частично за пределами многоугольника, то у вас есть проблема.
@Richard: Вот почему квалификация около 180 градусов. Если вы отрежете треугольник за пределами многоугольника, вы получите слишком много градусов.
возможно, вам придется лучше описать, как вы находите ракурс. В плоской геометрии нет возможности иметь 3 точки как часть треугольника и иметь любой угол или комбинацию углов, превышающих 180 градусов - проверка кажется бессмысленной.
@Richard: На вашем многоугольнике у вас есть угол каждого соединения. Если соответствующий треугольник будет лежать за пределами многоугольника, угол между двумя сегментами будет больше 180 градусов.
Вы имеете в виду, что внутренний угол двух смежных сегментов кромки будет больше 180 градусов.
Ага - я смотрю на углы, если смотреть изнутри многоугольника. Если предполагаемый треугольник на самом деле лежит за пределами многоугольника, у вас будут три угла больше 180, если смотреть с этой точки обзора. Тем не менее, достаточно протестировать первое.
Один из способов сделать это - разложить многоугольник на треугольники, вычислить площадь треугольников и принять сумму как площадь многоугольника.
Убедитесь, что вы отрицаете площадь треугольника, если следующая точка движется «назад».
Или сделать контур интегральный. Теорема Стокса позволяет выразить интеграл площадей как контурный интеграл. Маленькая квадратура Гаусса и ваш дядя Боб.
Набор точек без каких-либо других ограничений не обязательно однозначно определяет многоугольник.
Итак, сначала вам нужно решить, какой многоугольник построить из этих точек - возможно, выпуклую оболочку? 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 Площадь
Ссылка в посте мертвая. У кого-нибудь есть другая?
Связанное обсуждение в списке рассылки [email protected] мне недоступно. Скопировал сообщение из Google Cache: gist.github.com/1200393
Вот еще одна ссылка для объяснения. mathopenref.com/coordpolygonarea.html
имеет значение порядок баллов? Я имею в виду, должно ли это быть против часовой стрелки или по часовой стрелке или не имеет значения?
@ perfectionm1ng переключение направлений перевернуло бы знак в сумме, но abs() убирает знак.
Ограничения: этот метод даст неправильный ответ для самопересекающихся многоугольников, когда одна сторона пересекает другую, как показано справа. Однако он будет работать правильно для треугольников, правильных и неправильных многоугольников, выпуклых или вогнутых многоугольников. (mathopenref.com/coordpolygonarea.html)
«Неправильный» ответ - это вопрос определения. Например, если вы таким образом вычислили площадь пентаграммы, она не учитывала бы площадь центрального пятиугольника. Но если вы визуализировали заполненную пентаграмму, например, SVG, он также оставил бы этот пятиугольник незаполненным! Я согласен с тем, что стоит упомянуть, что этот ответ дает абсолютное значение области подписанный.
Это также известно в Википедии как Формула шнурков.
Я начал писать этот вопрос, но потом понял, что ответ на него уже был в ответе Дария. Надеюсь, мой комментарий может помочь кому-то еще, у кого есть этот вопрос; при наличии всего 4 точек вогнутый многоугольник неоднозначен; рассмотрим точки (0,0), (-1,-1),(1,0), and (0,1); область зависит от того, какие 2 точки подключены к (0,0) посередине. Дариус ответил на это «неявным переходом от последней вершины к первой», потому что порядок говорит вам, с какими двумя другими точками (0,0) примыкает.
Чтобы расширить области триангуляции и суммирования треугольников, они работают, если у вас есть выпуклый многоугольник ИЛИ вы случайно выбрали точку, которая не создает линий для каждой другой точки, пересекающей многоугольник.
Для обычного непересекающегося многоугольника необходимо просуммировать векторное произведение векторов (контрольная точка, точка 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, тем больше будет его площадь.
Это правильная математическая перестановка описанного выше алгоритма с сохранением некоторых умножений. Вы правы, но площади, определяемые другими вершинами, будут вычитаться. Но это действительно может привести к снижению точности.
Извините, но я не думаю, что это правильно. Достаточно взглянуть на цикл, чтобы увидеть, что он не может работать. Вот пример программы, которая демонстрирует, что результат второго алгоритма полностью меняется в зависимости от перемещения многоугольника по оси X: pastebin.com/Mb8uQpz5
Я проверил образец программы, используя ваши значения, и не вижу разницы в площади. Я вижу разницу между вашим кодом и вторым алгоритмом: условие цикла for i <= N, а не i <n. Это может объяснить, почему вы не получаете ожидаемого результата.
Что вы упустили из виду, так это то, что в сложении всегда есть отрицательные члены из-за вычитания y. Рассмотрим любую двумерную многоугольную форму и сравните значения y последовательных вершин. Вы увидите, что какое-то вычитание даст отрицательное значение, а какое-то положительное.
Действительно, этот последний абзац - это то, о чем я не мог осмыслить! С i <= N это работает. Спасибо за терпение, беру все обратно :)
Без проблем. Я рада быть полезной. В этом цель StackExchange. Кроме того, вы могли найти ошибку или неправильный ответ, и в этом случае вы были бы мне полезны. :)
Кстати, область, возвращаемая алгоритмом, является «подписанной» (отрицательной или положительной в зависимости от порядка точек), поэтому, если вы хотите всегда положительную область, просто используйте абсолютное значение.
Первый алгоритм опасен. После первой итерации вы можете получить доступ за массивом, если есть только 4 точки.
независимое от языка решение:
ДАННЫЙ: многоугольник ВСЕГДА может быть составлен из n-2 треугольников, которые не перекрываются (n = количество точек ИЛИ сторон). 1 треугольник = 3-сторонний многоугольник = 1 треугольник; 1 квадрат = 4-сторонний многоугольник = 2 треугольника; и т. д. до тошноты QED
следовательно, многоугольник можно уменьшить, «отрубив» треугольники, и общая площадь будет суммой площадей этих треугольников. попробуйте это с листом бумаги и ножницами, лучше всего, если вы сможете визуализировать процесс, прежде чем следовать.
если вы возьмете любые 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 человека. Расскажите, чем ваш ответ лучше, чем любой из уже опубликованных ответов.
Это пример на c, а не на python. Не лучше, но приятно иметь его на разных языках
Эта страница показывает, что формула

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

Если вы выпишете несколько терминов и сгруппируете их в соответствии с общими факторами 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.
Реализация Формула шнурков может быть выполнена в 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 принимает два аргумента, а вы вызываете его с помощью одного.
Как описано здесь: 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
Термин «площадь поверхности» немного вводит в заблуждение. Кажется, вам нужна только (обычная) область. В 3D площадь поверхности - это площадь внешней поверхности, поэтому естественным двухмерным обобщением этой концепции будет длина периметра многоугольника, что явно не то, что вы ищете.