# 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 - point_2
delta_y = point_1 - point_2
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, triangle)
side_2 = distance(triangle, triangle)
side_3 = distance(triangle, triangle)
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 * q - p * q
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:
{"ft_lang_label":"__label__en","ft_lang_prob":0.7121355,"math_prob":0.9983291,"size":3064,"snap":"2020-34-2020-40","text_gpt3_token_len":993,"char_repetition_ratio":0.13627452,"word_repetition_ratio":0.021186441,"special_character_ratio":0.3874021,"punctuation_ratio":0.1940532,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.99936634,"pos_list":[0,1,2,3,4],"im_url_duplicate_count":[null,6,null,6,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2020-08-07T03:42:07Z\",\"WARC-Record-ID\":\"<urn:uuid:2f7922af-8669-4c0d-9472-8021ad5ab9b1>\",\"Content-Length\":\"159462\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:f87ada9e-2fb5-4d0b-9fa3-329ed55a5dd4>\",\"WARC-Concurrent-To\":\"<urn:uuid:62f282d3-140e-435a-a4df-be726b61859f>\",\"WARC-IP-Address\":\"151.101.193.69\",\"WARC-Target-URI\":\"https://codereview.stackexchange.com/questions/88010/area-of-an-irregular-polygon?noredirect=1\",\"WARC-Payload-Digest\":\"sha1:EGO33FXN75YHDQUTDQQNXQGZPJBHUDMF\",\"WARC-Block-Digest\":\"sha1:LVM44W4NQYOOZITZEGFLVD2KLDDCMFKG\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2020/CC-MAIN-2020-34/CC-MAIN-2020-34_segments_1596439737152.0_warc_CC-MAIN-20200807025719-20200807055719-00550.warc.gz\"}"}