Вычислить площадь полигона по заданным (x,y) координатам

у меня есть набор точек и я хотел бы знать, есть ли функция (для удобства и, вероятно, скорости), которая может вычислить область, заключенную в набор точек.

например:

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

points = zip(x,y)

дано points площадь должна быть приблизительно равна (pi-2)/4. Может быть, есть что-то от scipy, matplotlib, numpy, shapely и т. д. сделать это? Я не буду сталкиваться с отрицательными значениями для координат x или y... и они будут полигоны без какой-либо определенной функции.

EDIT:

точки, скорее всего, не будут в любом указанном порядке (по часовой стрелке или против часовой стрелки) и могут быть довольно сложными, поскольку они представляют собой набор координат utm из шейп-файла под набором границ

6 ответов


реализация шнурки формуле можно сделать Numpy. Предполагая эти вершины:

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

мы можем переопределить функцию в numpy, чтобы найти область:

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

избежать for loop делает эту функцию ~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.

синхронизация выполняется в ноутбуке Jupyter.


можно использовать шнурки формуле, например

def PolygonArea(corners):
    n = len(corners) # of corners
    area = 0.0
    for i in range(n):
        j = (i + 1) % n
        area += corners[i][0] * corners[j][1]
        area -= corners[j][0] * corners[i][1]
    area = abs(area) / 2.0
    return area

# examples
corners = [(2.0, 1.0), (4.0, 5.0), (7.0, 8.0)]

это работает только для простых многоугольников


  • Если у вас полигон с отверстиями : вычислить площадь внешнего кольца и subtrack области внутреннего кольца

  • Если у вас самопересекающиеся кольца: вы должны разложить их на простые сектора


анализируя ответ Махди, я пришел к выводу, что большая часть времени была потрачена на выполнение np.roll(). Удалив необходимость рулона и все еще используя numpy, я получил время выполнения до 4-5μs за цикл по сравнению с 41μs Махди (для сравнения функция Махди заняла в среднем 37μs на моей машине).

def polygon_area(x,y):
    correction = x[-1] * y[0] - y[-1]* x[0]
    main_area = np.dot(x[:-1], y[1:]) - np.dot(y[:-1], x[1:])
    return 0.5*np.abs(main_area + correction)

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

критерии:

10000 iterations
PolyArea(x,y): 37.075µs per loop
polygon_area(x,y): 4.665µs per loop

время было сделано с помощью time модуль time.clock()


в приведенном выше коде есть ошибка, так как он не принимает абсолютных значений на каждой итерации. Приведенный выше код всегда возвращает ноль. (Математически это разница между взятием подписанной области или продукта Клина и фактической областью http://en.wikipedia.org/wiki/Exterior_algebra.) Вот другой код.

def area(vertices):
    n = len(vertices) # of corners
    a = 0.0
    for i in range(n):
        j = (i + 1) % n
        a += abs(vertices[i][0] * vertices[j][1]-vertices[j][0] * vertices[i][1])
    result = a / 2.0
    return result

Это намного проще, для регулярных полигонов:

import math

def area_polygon(n, s):
    return 0.25 * n * s**2 / math.tan(math.pi/n)

так как формула ¼ n s2/tan(π / n). Учитывая количество сторон, n и длину каждой стороны, s


на основе

https://www.mathsisfun.com/geometry/area-irregular-polygons.html

def _area_(coords):
    t=0
    for count in range(len(coords)-1):
        y = coords[count+1][1] + coords[count][1]
        x = coords[count+1][0] - coords[count][0]
        z = y * x
        t += z
    return abs(t/2.0)

a=[(5.09,5.8), (1.68,4.9), (1.48,1.38), (4.76,0.1), (7.0,2.83), (5.09,5.8)]
print _area_(a)

фишка в том, что первая координата должна быть последней.