Determine the area of a geodesic polygon
Arbitrarily complex polygons are allowed. In the case of self-intersecting polygons the area is accumulated "algebraically", e.g., the areas of the 2 loops in a figure-8 polygon will partially cancel. There's no need to "close" the polygon by repeating the first vertex. The area returned is signed with counter-clockwise traversal being treated as positive.
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
real(kind=wp), | intent(in) | :: | a |
the equatorial radius (meters). |
||
real(kind=wp), | intent(in) | :: | f |
the flattening of the ellipsoid. Setting |
||
real(kind=wp), | intent(in) | :: | lats(n) |
an array of the latitudes of the vertices (degrees). lats should be in the range [-90 deg, 90 deg]. |
||
real(kind=wp), | intent(in) | :: | lons(n) |
an array of the longitudes of the vertices (degrees). |
||
integer, | intent(in) | :: | n |
number of points |
||
real(kind=wp), | intent(out) | :: | AA |
the (signed) area of the polygon (). |
||
real(kind=wp), | intent(out) | :: | PP |
the perimeter of the polygon. |
subroutine area(a, f, lats, lons, n, AA, PP) integer, intent(in) :: n !! number of points real(wp), intent(in) :: a !! the equatorial radius (meters). real(wp), intent(in) :: f !! the flattening of the ellipsoid. Setting `f = 0` gives !! a sphere. Negative `f` gives a prolate ellipsoid. real(wp), intent(in) :: lats(n) !! an array of the latitudes of the vertices (degrees). !! lats should be in the range [-90 deg, 90 deg]. real(wp), intent(in) :: lons(n) !! an array of the longitudes of the vertices (degrees). real(wp), intent(out) :: AA !! the (signed) area of the polygon (\(m^2\)). real(wp), intent(out) :: PP !! the perimeter of the polygon. integer :: i, outmask, cross real(wp) :: s12, azi1, azi2, dummy1,dummy2,dummy3,dummy4, SS12, b, e2, c2, area0, & Aacc(2), Pacc(2) outmask = 8 Aacc = 0.0_wp Pacc = 0.0_wp cross = 0 do i = 0, n-1 call inverse(a, f, lats(i+1), lons(i+1), & lats(mod(i+1,n)+1), lons(mod(i+1,n)+1), & s12, azi1, azi2, outmask, dummy1, dummy2, dummy3, dummy4, SS12) call accadd(Pacc, s12) call accadd(Aacc, -SS12) cross = cross + transit(lons(i+1), lons(mod(i+1,n)+1)) end do PP = Pacc(1) b = a * (1.0_wp - f) e2 = f * (2.0_wp - f) if (e2 == 0.0_wp) then c2 = a**2 else if (e2 > 0.0_wp) then c2 = (a**2 + b**2 * atanh(sqrt(e2)) / sqrt(e2)) / 2.0_wp else c2 = (a**2 + b**2 * atan(sqrt(abs(e2))) / sqrt(abs(e2))) / 2.0_wp end if area0 = 4.0_wp * pi * c2 call accrem(Aacc, area0) if (mod(abs(cross), 2) == 1) then if (Aacc(1) < 0.0_wp) then call accadd(Aacc, +area0/2.0_wp) else call accadd(Aacc, -area0/2.0_wp) end if end if if (Aacc(1) > area0/2.0_wp) then call accadd(Aacc, -area0) else if (Aacc(1) <= -area0/2.0_wp) then call accadd(Aacc, +area0) end if AA = Aacc(1) end subroutine area