Skip to content

Commit e8002eb

Browse files
committed
feat: implement shoelace formula for polygon area calculation
1 parent e2a78d4 commit e8002eb

File tree

1 file changed

+70
-0
lines changed

1 file changed

+70
-0
lines changed

maths/shoelace_area.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""
2+
Shoelace formula (Gauss's area formula) for polygon area.
3+
4+
The function accepts an iterable of (x, y) pairs and returns the polygon area
5+
as a non-negative float.
6+
7+
References:
8+
- https://en.wikipedia.org/wiki/Shoelace_formula
9+
"""
10+
11+
from __future__ import annotations
12+
13+
from collections.abc import Iterable, Sequence
14+
15+
16+
def shoelace_area(points: Iterable[tuple[float, float]]) -> float:
17+
"""
18+
Compute the area of a simple polygon using the shoelace formula.
19+
20+
Parameters
21+
----------
22+
points:
23+
Iterable of (x, y) coordinate pairs. Points may be ints or floats.
24+
The polygon is assumed closed (the function will wrap the last point
25+
to the first).
26+
27+
Returns
28+
-------
29+
float
30+
Non-negative area of the polygon.
31+
32+
Raises
33+
------
34+
ValueError
35+
If fewer than 3 points are provided.
36+
TypeError
37+
If points are not pairs of numbers.
38+
39+
Examples
40+
>>> shoelace_area([(0, 0), (4, 0), (0, 3)])
41+
6.0
42+
>>> shoelace_area([(0, 0), (1, 0), (1, 1), (0, 1)])
43+
1.0
44+
>>> shoelace_area(list(reversed([(0, 0), (2, 0), (2, 2), (0, 2)])))
45+
4.0
46+
>>> shoelace_area([(0, 0), (2, 0), (2, 2), (0, 2)])
47+
4.0
48+
"""
49+
pts = list(points)
50+
n = len(pts)
51+
if n < 3:
52+
raise ValueError("At least 3 points are required to form a polygon")
53+
54+
try:
55+
coords: Sequence[tuple[float, float]] = [(float(x), float(y)) for x, y in pts]
56+
except Exception as exc:
57+
raise TypeError("points must be an iterable of (x, y) numeric pairs") from exc
58+
59+
s = 0.0
60+
for i in range(n):
61+
x1, y1 = coords[i]
62+
x2, y2 = coords[(i + 1) % n]
63+
s += x1 * y2 - x2 * y1
64+
65+
return abs(s) / 2.0
66+
67+
68+
if __name__ == "__main__":
69+
example = [(0, 0), (4, 0), (0, 3)]
70+
print("example area:", shoelace_area(example))

0 commit comments

Comments
 (0)