# Area of an irregular polygon

"""
Provides a way to caculate the area of an arbitrary
n-sided irregular polygon.
"""
import doctest
import math

def heron(a,b,c):
"""
Uses the heron formula to calculate the area
of the triangle where a,b and c are the side
lengths.

>>> heron(3, 4, 5)
6.0
>>> heron(7, 10, 5).__round__(2)
16.25
"""
s = (a + b + c) / 2
return math.sqrt(s * (s - a) * (s - b) * (s - c))

def pytagoras(a, b):
"""
Given the cathets finds the hypotenusas.

>>> pytagoras(3, 4)
5.0
"""
return math.sqrt(a**2 + b**2)

def distance(point_1, point_2):
"""
Computes the cartesian distance between two points.

>>> distance((0,0), (5,0))
5.0
"""
delta_x = point_1[0] - point_2[0]
delta_y = point_1[1] - point_2[1]
return pytagoras(delta_x, delta_y)

def triangle_area(triangle):
"""
Wraps heron by allowing points inputs instead
of sides lengths inputs.

>>> triangle_area([(0,0), (0,3), (4,0)])
6.0
"""
side_1 = distance(triangle[0], triangle[1])
side_2 = distance(triangle[1], triangle[2])
side_3 = distance(triangle[2], triangle[0])
return heron(side_1, side_2, side_3)

def triplets(list_):
"""
Yields items from a list in groups of 3.

>>> list(triplets(range(6)))
[(0, 1, 2), (1, 2, 3), (2, 3, 4), (3, 4, 5)]
"""
for index, item in enumerate(list_[:-2]):
yield item, list_[index + 1], list_[index + 2]

def polygon_area(polygon):
"""
Calculates the area of an n-sided polygon by
decomposing it into triangles. Input must be
a list of points.

>>> polygon_area([(0,0), (0,5), (3,0), (3, 5)])
15.0
"""
return sum(triangle_area(triangle)
for triangle in triplets(polygon))

def _main():
doctest.testmod()

if __name__ == "__main__":
_main()

• You accepted this answer but you don't seem to have taken notice of it — several of the comments there also apply here. – Gareth Rees Apr 26 '15 at 11:25
• @GarethRees sorry I did not think that I was reusing similar functions over again without looking at the built-ins... I will think about wheter the standard library contains them next time – Caridorc Apr 26 '15 at 11:32
• Also, point 5 from the earlier answer is still relevant here. – Gareth Rees Apr 26 '15 at 11:35

The "shoelace" formula finds the area of a simple polygon:

from __future__ import division

def polygon_area(points):
"""Return the area of the polygon whose vertices are given by the
sequence points.

"""
area = 0
q = points[-1]
for p in points:
area += p[0] * q[1] - p[1] * q[0]
q = p
return area / 2

if __name__ == '__main__':
square = [(0,0), (0,1), (1,1), (1,0)]
irregular = [(1,1), (1,5), (2,5), (5,1)]
print('Unit square area: {}'.format(polygon_area(square)))
print('Irregular polygon area: {}'.format(polygon_area(irregular)))


This outputs:

Unit square area: 1.0
Irregular polygon area: 10.0


The algorithm is wrong! Consider this polygon:

It's easy to see that this an area of 10, but:

>>> polygon_area([(1,1), (1,5), (2,5), (5,1)])
3.9999999999999973


That's because the polygon_area algorithm adds the two red triangles shown in the figure below, each of which has area 2: