Skip to content

Commit

Permalink
Switch return type to be tuple
Browse files Browse the repository at this point in the history
  • Loading branch information
skygering committed Oct 2, 2023
1 parent 868e9fa commit fe1d6da
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 48 deletions.
50 changes: 22 additions & 28 deletions src/methods/centroid.jl
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ function centroid_and_length(
::Union{GI.LineStringTrait, GI.LinearRingTrait},
geom,
)
T = Float64
T = typeof(GI.x(GI.getpoint(geom, 1)))
# Initialize starting values
xcentroid = T(0)
ycentroid = T(0)
Expand All @@ -133,7 +133,7 @@ function centroid_and_length(
end
xcentroid /= length
ycentroid /= length
return GI.Point(xcentroid, ycentroid), length
return (xcentroid, ycentroid), length
end

"""
Expand All @@ -149,7 +149,7 @@ function centroid_and_area(
::Union{GI.LineStringTrait, GI.LinearRingTrait},
geom,
)
T = Float64
T = typeof(GI.x(GI.getpoint(geom, 1)))
# Check that the geometry is closed
@assert(
GI.getpoint(geom, 1) == GI.getpoint(geom, GI.ngeom(geom)),
Expand All @@ -175,7 +175,7 @@ function centroid_and_area(
area /= 2
xcentroid /= 6area
ycentroid /= 6area
return GI.Point(xcentroid, ycentroid), abs(area)
return (xcentroid, ycentroid), abs(area)
end

"""
Expand All @@ -184,30 +184,24 @@ end
Returns the centroid and area of a given polygon.
"""
function centroid_and_area(::GI.PolygonTrait, geom)
T = Float64
# Initialize starting values
xcentroid = T(0)
ycentroid = T(0)
area = T(0)
# Exterior polygon centroid and area
ext_centroid, ext_area = centroid_and_area(GI.getexterior(geom))
area += ext_area
# Exterior ring's centroid and area
(xcentroid, ycentroid), area = centroid_and_area(GI.getexterior(geom))
# Weight exterior centroid by area
xcentroid += GI.x(ext_centroid) * ext_area
ycentroid += GI.y(ext_centroid) * ext_area
xcentroid *= area
ycentroid *= area
# Loop over any holes within the polygon
for hole in GI.gethole(geom)
# Hole polygon's centroid and area
interior_centroid, interior_area = centroid_and_area(hole)
(xinterior, yinterior), interior_area = centroid_and_area(hole)
# Accumulate the area component into `area`
area -= interior_area
# Weighted average of centroid components
xcentroid -= GI.x(interior_centroid) * interior_area
ycentroid -= GI.y(interior_centroid) * interior_area
xcentroid -= xinterior * interior_area
ycentroid -= yinterior * interior_area
end
xcentroid /= area
ycentroid /= area
return GI.Point(xcentroid, ycentroid), area
return (xcentroid, ycentroid), area
end

"""
Expand All @@ -216,22 +210,22 @@ end
Returns the centroid and area of a given multipolygon.
"""
function centroid_and_area(::GI.MultiPolygonTrait, geom)
T = Float64
# Initialize starting values
xcentroid = T(0)
ycentroid = T(0)
area = T(0)
# First polygon's centroid and area
(xcentroid, ycentroid), area = centroid_and_area(GI.getpolygon(geom, 1))
# Weight first polygon's centroid by area
xcentroid *= area
ycentroid *= area
# Loop over any polygons within the multipolygon
for poly in GI.getpolygon(geom)
for i in 2:GI.ngeom(geom) #poly in GI.getpolygon(geom)
# Polygon centroid and area
poly_centroid, poly_area = centroid_and_area(poly)
(xpoly, ypoly), poly_area = centroid_and_area(GI.getpolygon(geom, i))
# Accumulate the area component into `area`
area += poly_area
# Weighted average of centroid components
xcentroid += GI.x(poly_centroid) * poly_area
ycentroid += GI.y(poly_centroid) * poly_area
xcentroid += xpoly * poly_area
ycentroid += ypoly * poly_area
end
xcentroid /= area
ycentroid /= area
return GI.Point(xcentroid, ycentroid), area
return (xcentroid, ycentroid), area
end
38 changes: 18 additions & 20 deletions test/methods/centroid.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
l1 = LG.LineString([[0.0, 0.0], [10.0, 0.0], [10.0, 10.0]])
c1, len1 = GO.centroid_and_length(l1)
c1_from_LG = LG.centroid(l1)
@test GI.x(c1) GI.x(c1_from_LG)
@test GI.y(c1) GI.y(c1_from_LG)
@test c1[1] GI.x(c1_from_LG)
@test c1[2] GI.y(c1_from_LG)
@test len1 20.0

# Spiral line string
l2 = LG.LineString([[0.0, 0.0], [2.5, -2.5], [-5.0, -3.0], [-4.0, 6.0], [10.0, 10.0], [12.0, -14.56]])
c2, len2 = GO.centroid_and_length(l2)
c2_from_LG = LG.centroid(l2)
@test GI.x(c2) GI.x(c2_from_LG)
@test GI.y(c2) GI.y(c2_from_LG)
@test c2[1] GI.x(c2_from_LG)
@test c2[2] GI.y(c2_from_LG)
@test len2 59.3090856788928

# Test that non-closed line strings throw an error for centroid_and_area
Expand All @@ -22,15 +22,15 @@
r1 = LG.LinearRing([[0.0, 0.0], [3456.0, 7894.0], [6291.0, 1954.0], [0.0, 0.0]])
c3 = GO.centroid(r1)
c3_from_LG = LG.centroid(r1)
@test GI.x(c3) GI.x(c3_from_LG)
@test GI.y(c3) GI.y(c3_from_LG)

@test c3[1] GI.x(c3_from_LG)
@test c3[2] GI.y(c3_from_LG)
end

@testset "Polygons" begin
# Basic rectangle
p1 = AG.fromWKT("POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))")
c1 = GO.centroid(p1)
c1 .≈ (5, 5)
@test GI.x(c1) 5
@test GI.y(c1) 5

Expand All @@ -41,8 +41,8 @@ end
]])
c2, area2 = GO.centroid_and_area(p2)
c2_from_LG = LG.centroid(p2)
@test GI.x(c2) GI.x(c2_from_LG)
@test GI.y(c2) GI.y(c2_from_LG)
@test c2[1] GI.x(c2_from_LG)
@test c2[2] GI.y(c2_from_LG)
@test area2 LG.area(p2)

# Randomly generated polygon with lots of sides
Expand All @@ -55,8 +55,8 @@ end
]])
c3, area3 = GO.centroid_and_area(p3)
c3_from_LG = LG.centroid(p3)
@test GI.x(c3) GI.x(c3_from_LG)
@test GI.y(c3) GI.y(c3_from_LG)
@test c3[1] GI.x(c3_from_LG)
@test c3[2] GI.y(c3_from_LG)
@test area3 LG.area(p3)

# Polygon with one hole
Expand All @@ -66,8 +66,8 @@ end
])
c4, area4 = GO.centroid_and_area(p4)
c4_from_LG = LG.centroid(p4)
@test GI.x(c4) GI.x(c4_from_LG)
@test GI.y(c4) GI.y(c4_from_LG)
@test c4[1] GI.x(c4_from_LG)
@test c4[2] GI.y(c4_from_LG)
@test area4 LG.area(p4)

# Polygon with two holes
Expand All @@ -78,8 +78,8 @@ end
])
c5 = GO.centroid(p5)
c5_from_LG = LG.centroid(p5)
@test GI.x(c5) GI.x(c5_from_LG)
@test GI.y(c5) GI.y(c5_from_LG)
@test c5[1] GI.x(c5_from_LG)
@test c5[2] GI.y(c5_from_LG)

# Same polygon as P5 but using a GeoInterface polygon
p6 = GI.Polygon([
Expand All @@ -88,9 +88,7 @@ end
[(-3.0, -9.0), (3.0, -9.0), (3.0, -8.5), (-3.0, -8.5), (-3.0, -9.0)],
])
c6 = GO.centroid(p6)
@test GI.x(c6) GI.x(c5)
@test GI.y(c6) GI.y(c5)

@test all(c5 .≈ c6)
end
@testset "MultiPolygons" begin
# Combine poylgons made above
Expand All @@ -106,7 +104,7 @@ end
])
c1, area1 = GO.centroid_and_area(m1)
c1_from_LG = LG.centroid(m1)
@test GI.x(c1) GI.x(c1_from_LG)
@test GI.y(c1) GI.y(c1_from_LG)
@test c1[1] GI.x(c1_from_LG)
@test c1[2] GI.y(c1_from_LG)
@test area1 LG.area(m1)
end

0 comments on commit fe1d6da

Please sign in to comment.