Skip to content

Commit 1781260

Browse files
authored
BUG: Fix handling of polygon holes when calculating area in Geod (#686)
1 parent 9222735 commit 1781260

File tree

2 files changed

+22
-12
lines changed

2 files changed

+22
-12
lines changed

pyproj/geod.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -530,9 +530,11 @@ def geometry_area_perimeter(
530530
531531
.. note:: lats should be in the range [-90 deg, 90 deg].
532532
533-
.. warning:: The area returned is signed with counter-clockwise traversal being
534-
treated as positive. You can use `shapely.ops.orient` to modify the
535-
orientation.
533+
.. warning:: The area returned is signed with counter-clockwise (CCW) traversal
534+
being treated as positive. For polygons, holes should use the
535+
opposite traversal to the exterior (if the exterior is CCW, the
536+
holes/interiors should be CW). You can use `shapely.ops.orient` to
537+
modify the orientation.
536538
537539
If it is a Polygon, it will return the area and exterior perimeter.
538540
It will subtract the area of the interior holes.
@@ -548,13 +550,13 @@ def geometry_area_perimeter(
548550
>>> poly_area, poly_perimeter = geod.geometry_area_perimeter(
549551
... Polygon(
550552
... LineString([
551-
... Point(1, 1), Point(1, 10), Point(10, 10), Point(10, 1)
553+
... Point(1, 1), Point(10, 1), Point(10, 10), Point(1, 10)
552554
... ]),
553555
... holes=[LineString([Point(1, 2), Point(3, 4), Point(5, 2)])],
554556
... )
555557
... )
556558
>>> f"{poly_area:.3f} {poly_perimeter:.3f}"
557-
'-944373881400.339 3979008.036'
559+
'944373881400.339 3979008.036'
558560
559561
560562
Parameters
@@ -583,7 +585,7 @@ def geometry_area_perimeter(
583585
# subtract area of holes
584586
for hole in geometry.interiors:
585587
area, _ = self.geometry_area_perimeter(hole, radians=radians)
586-
total_area -= area
588+
total_area += area
587589
return total_area, total_perimeter
588590
# multi geometries
589591
elif hasattr(geometry, "geoms"):

test/test_geod.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
Point,
2222
Polygon,
2323
)
24+
from shapely.geometry.polygon import orient
2425

2526
SHAPELY_LOADED = True
2627
except ImportError:
@@ -380,13 +381,20 @@ def test_geometry_area_perimeter__polygon__radians():
380381
@skip_shapely
381382
def test_geometry_area_perimeter__polygon__holes():
382383
geod = Geod(ellps="WGS84")
384+
385+
polygon = Polygon(
386+
LineString([Point(1, 1), Point(1, 10), Point(10, 10), Point(10, 1)]),
387+
holes=[LineString([Point(1, 2), Point(3, 4), Point(5, 2)])],
388+
)
389+
383390
assert_almost_equal(
384-
geod.geometry_area_perimeter(
385-
Polygon(
386-
LineString([Point(1, 1), Point(1, 10), Point(10, 10), Point(10, 1)]),
387-
holes=[LineString([Point(1, 2), Point(3, 4), Point(5, 2)])],
388-
)
389-
),
391+
geod.geometry_area_perimeter(orient(polygon, 1)),
392+
(944373881400.3394, 3979008.0359657984),
393+
decimal=2,
394+
)
395+
396+
assert_almost_equal(
397+
geod.geometry_area_perimeter(orient(polygon, -1)),
390398
(-944373881400.3394, 3979008.0359657984),
391399
decimal=2,
392400
)

0 commit comments

Comments
 (0)