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

Create a PolygonContents fix that fixes the contents of polygons to be linear rings #168

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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 src/GeometryOps.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ include("transformations/transform.jl")
include("transformations/correction/geometry_correction.jl")
include("transformations/correction/closed_ring.jl")
include("transformations/correction/intersecting_polygons.jl")
include("transformations/correction/polygon_contents.jl")

# Import all names from GeoInterface and Extents, so users can do `GO.extent` or `GO.trait`.
for name in names(GeoInterface)
Expand Down
18 changes: 16 additions & 2 deletions src/methods/clipping/union.jl
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ function _union(
if !isnothing(fix_multipoly) # Fix multipoly_b to prevent repeated regions in the output
multipoly_b = fix_multipoly(multipoly_b)
end
polys = [tuples(poly_a, T)]
polys = [fix(tuples(poly_a, T); corrections = (PolygonContents(), ))]
for poly_b in GI.getpolygon(multipoly_b)
if intersects(polys[1], poly_b)
# If polygons intersect and form a new polygon, swap out polygon
Expand All @@ -229,7 +229,7 @@ function _union(
end
else
# If they don't intersect, poly_b is now a part of the union as its own polygon
push!(polys, tuples(poly_b, T))
push!(polys, fix(tuples(poly_b, T); corrections = (PolygonContents(), )))
end
end
return polys
Expand Down Expand Up @@ -267,6 +267,20 @@ function _union(
return polys
end

function _union(
target::TraitTarget{GI.MultiPolygonTrait}, ::Type{T},
::GI.MultiPolygonTrait, multipoly_a,
::GI.MultiPolygonTrait, multipoly_b;
fix_multipoly = UnionIntersectingPolygons(), kwargs...,
) where T
return GI.MultiPolygon(_union( # this is the method directly above, and returns a vector of polygons
TraitTarget{GI.PolygonTrait}(), T,
GI.MultiPolygonTrait(), multipoly_a,
GI.MultiPolygonTrait(), multipoly_b;
fix_multipoly, kwargs...
))
end

# Many type and target combos aren't implemented
function _union(
::TraitTarget{Target}, ::Type{T},
Expand Down
13 changes: 12 additions & 1 deletion src/transformations/correction/geometry_correction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,18 @@ application_level(gc::GeometryCorrection) = error("Not implemented yet for $(gc)

(gc::GeometryCorrection)(trait::GI.AbstractGeometryTrait, geometry) = error("Not implemented yet for $(gc) and $(trait).")

function fix(geometry; corrections = GeometryCorrection[ClosedRing(),], kwargs...)
"""
fix(x; corrections = GeometryCorrection[], kwargs...)

Apply the given corrections to `x`, and return the corrected version.

`x` may be a geometry, vector of geometries, feature collection, or table -
anything which [`apply`](@ref) will accept!

Some available corrections are: [`ClosedRing`](@ref), [`PolygonContents`](@ref), [`UnionIntersectingPolygons`](@ref), [`DiffIntersectingPolygons`](@ref).

"""
function fix(geometry; corrections = GeometryCorrection[PolygonContents(), ClosedRing(),], kwargs...)
traits = application_level.(corrections)
final_geometry = geometry
for Trait in (GI.PointTrait, GI.MultiPointTrait, GI.LineStringTrait, GI.LinearRingTrait, GI.MultiLineStringTrait, GI.PolygonTrait, GI.MultiPolygonTrait)
Expand Down
33 changes: 33 additions & 0 deletions src/transformations/correction/polygon_contents.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# # PolygonContents

export PolygonContents

#=
Polygons should only contain linear rings. This fix checks
whether the contents of the polygon are linear rings or linestrings,
and converts linestrings to linear rings.

It does **NOT** check whether the linear rings are valid - it only checks
the types of the polygon's constituent geometries. You can use the [`ClosedRing`](@ref)
geometry fix to check for validity after applying this fix.
=#

struct PolygonContents <: GeometryCorrection end

application_level(::PolygonContents) = GI.PolygonTrait

function (::PolygonContents)(::GI.PolygonTrait, polygon)
exterior = GI.getexterior(polygon)
fixed_exterior = _ls2lr(exterior)
holes = GI.gethole(polygon)
if isempty(holes)
return GI.Polygon([fixed_exterior])
end
fixed_holes = _ls2lr.(holes)
return GI.Polygon([fixed_exterior, fixed_holes...])
end

_ls2lr(x) = _ls2lr(GI.geomtrait(x), x)

_ls2lr(::GI.LineStringTrait, x) = GI.LinearRing(GI.getpoint(x))
_ls2lr(::GI.LinearRingTrait, x) = x
Loading