0
\$\begingroup\$
"""
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()
\$\endgroup\$
  • 2
    \$\begingroup\$ You accepted this answer but you don't seem to have taken notice of it — several of the comments there also apply here. \$\endgroup\$ – Gareth Rees Apr 26 '15 at 11:25
  • \$\begingroup\$ @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 \$\endgroup\$ – Caridorc Apr 26 '15 at 11:32
  • 1
    \$\begingroup\$ Also, point 5 from the earlier answer is still relevant here. \$\endgroup\$ – Gareth Rees Apr 26 '15 at 11:35
6
\$\begingroup\$

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
\$\endgroup\$
4
\$\begingroup\$

The algorithm is wrong! Consider this polygon:

Orange quadrilateral with vertices (1,1), (1,5), (2,5) and (5,1)

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:

Two red triangles with vertices (1,1), (1,5), (2,5) and (1,5), (2,5), (5,2) respectively superimposed on the orange quadrilateral.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.