So I was thinking of making a GUI in Python that calculates the area of a shape that the user draws. Therefore, I would need some sort of equation to find the area. I googled it and I found the Shoelace formula(made by Gauss himself); right here: https://en.m.wikipedia.org/wiki/Shoelace_formula

I read it and all of their examples are for polygons. But the user can draw circular shapes, so I did more research and found Pick's formula; right here: https://www.youtube.com/watch?v=vYmemgPa87I

And I think that Pick's formula is a lot easier to use. But what's the difference? Is there one better than the other or do they have their pros and cons? Thanks.


1 Answer 1


But what's the difference?

Pick's theorem works only if the polygon vertices have integer coordinates.

Shoelace formula works with any real coordinates.

If you have a sequence of tuples corresponding to the consecutive points along the path the user drew, then the Shoelace formula is trivial to implement.

Let's say path is that sequence, with path[0] being the starting point, and path[len(path)-1] the final point. Then, we can use the fact that in Python, path[len(path)-1] == path[-1]:

def pathArea(path):
    # Less than three points, and the area is zero.
    if len(path) < 3:
        return 0

    A = 0.0
    for i in range(0, len(path)):
        A += path[i-1][0] * path[i][1] - path[i][0] * path[i-1][1]

    return 0.5 * abs(A)

Mathematically, the above uses $$A = \frac{1}{2}\left\lvert \sum_{i=0}^{n-1} x_{i-1} y_{i} - x_{i} y_{i-1} \right\rvert$$ where $n$ is len(path), and $x_{-1} = x_{n-1}$ and $y_{-1} = y_{n-1}$ matching the final point in path.

When drawing, you can use line segments between the points, but note that you'll only want to add a new vertex if it differs from the previous one. So, if self.currentPath is the path being drawn, and newX and newY are the current coordinates being drawn, use

    if (self.currentPath is None) or (len(self.currentPath) < 1):
        self.currentPath = [ (newX, newY) ]
    elif (self.currentPath[-1][0] != newX) or (self.currentPath[-1][1] != newY):
        self.currentPath.append( (newX, newY) ]

so that the vertex list will not contain consecutive duplicate points.

Note that the above pathArea() function does not need the path to be closed, to start and end with the same point; there is an implicit line segment (polygon side) between the starting and the ending point.

If the user draws a closed figure with line segments poking out, drawing α instead of a nice circle, you will need to trim off the extra vertices. Otherwise the actual area calculated is that of a fish shape, as an extra line segment is added between the starting and ending points.

To do that, you need to find vertex $S$ near the beginning of the path, and vertex $E$ near the end of the path, such that the line segment from the vertex $S$ to the next vertex (from $(x_S , y_S)$ to $(x_{S+1}, y_{S+1})$), intersects the line segment from the vertex preceding $E$ to vertex $E$ (from $(x_{E-1}, y_{E-1})$ to $(x_E , y_E)$); with $S < E$. If you find the intersection, remove all initial vertices on the path up to $S$, and all vertices from $E$ to end, including both vertices $S$ and $E$, and prepend or append the intersection point to the path.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .