python - por - poligono irregular area y perimetro
Calcular área de polígono dado(x, y) coordenadas (6)
Tengo un conjunto de puntos y me gustaría saber si hay una función (por razones de conveniencia y probablemente de velocidad) que pueda calcular el área encerrada por un conjunto de puntos.
por ejemplo:
x = np.arange(0,1,0.001)
y = np.sqrt(1-x**2)
points = zip(x,y)
points
dados el área debe ser aproximadamente igual a (pi-2)/4
. Tal vez hay algo de scipy, matplotlib, numpy, shapely, etc. para hacer esto? No encontraré ningún valor negativo para las coordenadas x o y ... y serán polígonos sin ninguna función definida.
EDITAR:
lo más probable es que los puntos no estén en un orden específico (en el sentido de las agujas del reloj o en el sentido contrario a las agujas del reloj) y pueden ser bastante complejos, ya que son un conjunto de coordenadas utm de un shapefile bajo un conjunto de límites
Al analizar la respuesta de Mahdi, llegué a la conclusión de que la mayor parte del tiempo se pasaba haciendo np.roll()
. Al eliminar la necesidad de la tirada y seguir usando el número, el tiempo de ejecución se redujo a 4-5µs por bucle en comparación con los 41µs de Mahdi (para comparación, la función de Mahdi tomó un promedio de 37µs en mi máquina).
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)
Al calcular el término correccional y luego cortar las matrices, no es necesario rodar o crear una nueva matriz.
Puntos de referencia:
10000 iterations
PolyArea(x,y): 37.075µs per loop
polygon_area(x,y): 4.665µs per loop
La sincronización se realizó utilizando el módulo de time
y time.clock()
Esto es mucho más simple, para polígonos regulares:
import math
def area_polygon(n, s):
return 0.25 * n * s**2 / math.tan(math.pi/n)
ya que la fórmula es ¼ n s2 / tan (π / n). Dado el número de lados, n, y la longitud de cada lado, s
Hay un error en el código anterior ya que no toma valores absolutos en cada iteración. El código anterior siempre devolverá cero. (Matemáticamente, es la diferencia entre tomar el área firmada o el producto de cuña y el área real http://en.wikipedia.org/wiki/Exterior_algebra ). Aquí hay un código alternativo.
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
La implementación de la fórmula de Numpy
se podría hacer en Numpy
. Asumiendo estos vértices:
import numpy as np
x = np.arange(0,1,0.001)
y = np.sqrt(1-x**2)
Podemos redefinir la función en numpy para encontrar el área:
def PolyArea(x,y):
return 0.5*np.abs(np.dot(x,np.roll(y,1))-np.dot(y,np.roll(x,1)))
Y obteniendo resultados:
print PolyArea(x,y)
# 0.26353377782163534
Evitar el bucle hace que esta función sea PolygonArea
más rápida que 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.
La sincronización se realiza en el cuaderno Jupyter.
Puede utilizar la fórmula del cordón de zapato , por ejemplo
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)]
Esto solo funciona para polígonos simples.
Si tiene un polígono con orificios : calcule el área del anillo exterior y realice un seguimiento de las áreas de los anillos internos
Si tiene anillos de auto-intersección : tiene que descomponerlos en sectores simples
Residencia en
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)
El truco es que la primera coordenada también debe ser la última.