Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sg/area dist debug #33

Merged
merged 20 commits into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/Manifest.toml
/docs/build/
.vscode/
44 changes: 39 additions & 5 deletions src/methods/area.jl
Original file line number Diff line number Diff line change
Expand Up @@ -71,23 +71,53 @@ computed slighly differently for different geometries:
signed_area(geom) = signed_area(GI.trait(geom), geom)

# Points
area(::GI.PointTrait, point) = zero(typeof(GI.x(point)))
area(::GI.PointTrait, point) = GI.isempty(point) ?
0 : zero(typeof(GI.x(point)))

signed_area(trait::GI.PointTrait, point) = area(trait, point)

# MultiPoints
function area(::GI.MultiPointTrait, multipoint)
GI.isempty(multipoint) && return 0
np = GI.npoint(multipoint)
np == 0 && return 0
Copy link
Member

@rafaqz rafaqz Dec 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make area always return Float64 for type stability?

Another option is to check the type once at the start, then push it through as the first argument T to an _area(T, trait, geom) method that returns e.g. zero(T). We can let users specify it too if they need to

return zero(typeof(GI.x(GI.getpoint(multipoint, np))))
end

signed_area(trait::GI.MultiPointTrait, multipoint) = area(trait, multipoint)

# Curves
area(::CT, curve) where CT <: GI.AbstractCurveTrait =
zero(typeof(GI.x(GI.getpoint(curve, 1))))
function area(::CT, curve) where CT <: GI.AbstractCurveTrait
GI.isempty(curve) && return 0
np = GI.npoint(curve)
np == 0 && return 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

return zero(typeof(GI.x(GI.getpoint(curve, np))))
end

signed_area(trait::CT, curve) where CT <: GI.AbstractCurveTrait =
area(trait, curve)

# MultiCurves
function area(::MCT, multicurve) where MCT <: GI.AbstractMultiCurveTrait
GI.isempty(multicurve) && return 0
ng = GI.ngeom(multicurve)
ng == 0 && return 0
np = GI.npoint(GI.getgeom(multicurve, ng))
np == 0 && return 0
return zero(typeof(GI.x(GI.getpoint(GI.getgeom(multicurve, ng), np))))
end

signed_area(trait::MCT, curve) where MCT <: GI.AbstractMultiCurveTrait =
area(trait, curve)

# Polygons
area(trait::GI.PolygonTrait, geom) = abs(signed_area(trait, geom))

function signed_area(::GI.PolygonTrait, poly)
GI.isempty(poly) && return 0
s_area = _signed_area(GI.getexterior(poly))
area = abs(s_area)
area == 0 && return area
# Remove hole areas from total
for hole in GI.gethole(poly)
area -= abs(_signed_area(hole))
Expand All @@ -97,9 +127,12 @@ function signed_area(::GI.PolygonTrait, poly)
end

# MultiPolygons
area(::GI.MultiPolygonTrait, geom) =
sum((area(poly) for poly in GI.getpolygon(geom)))
area(::GI.MultiPolygonTrait, multipoly) =
sum((area(poly) for poly in GI.getpolygon(multipoly)), init = 0)

# GeometryCollections
area(::GI.GeometryCollectionTrait, collection) =
sum((area(geom) for geom in GI.getgeom(collection)), init = 0)
#=
Helper function:

Expand All @@ -111,6 +144,7 @@ to be closed.
function _signed_area(geom)
# Close curve, even if last point isn't explicitly repeated
np = GI.npoint(geom)
np == 0 && return 0
first_last_equal = equals(GI.getpoint(geom, 1), GI.getpoint(geom, np))
np -= first_last_equal ? 1 : 0
# Integrate the area under the curve
Expand Down
31 changes: 30 additions & 1 deletion test/methods/area.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
pt = LG.Point([0.0, 0.0])
empty_pt = LG.readgeom("POINT EMPTY")
mpt = LG.MultiPoint([[0.0, 0.0], [1.0, 0.0]])
empty_mpt = LG.readgeom("MULTIPOINT EMPTY")
l1 = LG.LineString([[0.0, 0.0], [0.5, 0.5], [1.0, 0.5]])
empty_l = LG.readgeom("LINESTRING EMPTY")
ml1 = LG.MultiLineString([[[0.0, 0.0], [0.5, 0.5], [1.0, 0.5]], [[0.0, 0.0], [0.0, 0.1]]])
empty_ml = LG.readgeom("MULTILINESTRING EMPTY")
empty_l = LG.readgeom("LINESTRING EMPTY")
r1 = LG.LinearRing([[0.0, 0.0], [1.0, 0.0], [1.0, 2.0], [0.0, 0.0]])
empty_r = LG.readgeom("LINEARRING EMPTY")
p1 = LG.Polygon([
[[10.0, 0.0], [30.0, 0.0], [30.0, 20.0], [10.0, 20.0], [10.0, 0.0]],
])
Expand All @@ -19,13 +27,23 @@ p4 = LG.Polygon([
[0.0, 5.0],
],
])
empty_p = LG.readgeom("POLYGON EMPTY")
mp1 = LG.MultiPolygon([p2, p4])

empty_mp = LG.readgeom("MULTIPOLYGON EMPTY")
c = LG.GeometryCollection([p1, p2, r1, empty_l])
empty_c = LG.readgeom("GEOMETRYCOLLECTION EMPTY")

# Points, lines, and rings have zero area
@test GO.area(pt) == GO.signed_area(pt) == LG.area(pt) == 0
# @test GO.area(empty_pt) == LG.area(empty_pt) == 0
@test GO.area(mpt) == GO.signed_area(mpt) == LG.area(mpt) == 0
@test GO.area(empty_mpt) == LG.area(empty_mpt) == 0
@test GO.area(l1) == GO.signed_area(l1) == LG.area(l1) == 0
@test GO.area(empty_l) == LG.area(empty_l) == 0
@test GO.area(ml1) == GO.signed_area(ml1) == LG.area(ml1) == 0
@test GO.area(empty_ml) == LG.area(empty_ml) == 0
@test GO.area(r1) == GO.signed_area(r1) == LG.area(r1) == 0
@test GO.area(empty_r) == LG.area(empty_r) == 0

# Polygons have non-zero area
# CCW polygons have positive signed area
Expand All @@ -41,5 +59,16 @@ a2 = LG.area(p2)
a4 = LG.area(p4)
@test GO.area(p4) == a4
@test GO.signed_area(p4) == -a4
# Empty polygon
@test GO.area(empty_p) == LG.area(empty_p) == 0
@test GO.signed_area(empty_p) == 0

# Multipolygon calculations work
@test GO.area(mp1) == a2 + a4
# Empty multipolygon
@test GO.area(empty_mp) == LG.area(empty_mp) == 0

# Geometry collection summed area
@test GO.area(c) == LG.area(c)
# Empty collection
@test GO.area(empty_c) == LG.area(empty_c) == 0
Loading