Closed Rings
export ClosedRing
A closed ring is a ring that has the same start and end point. This is a requirement for a valid polygon (technically, for a valid LinearRing). This correction is used to ensure that the polygon is valid.
The reason this operates on the polygon level is that several packages are loose about whether they return LinearRings (which is correct) or LineStrings (which is incorrect) for the contents of a polygon. Therefore, we decompose manually to ensure correctness.
Example
Many polygon providers do not close their polygons, which makes them invalid according to the specification. Quite a few geometry algorithms assume that polygons are closed, and leaving them open can lead to incorrect results!
For example, the following polygon is not valid:
import GeoInterface as GI
polygon = GI.Polygon([[(0, 0), (1, 0), (1, 1), (0, 1)]])
GeoInterface.Wrappers.Polygon{false, false, Vector{GeoInterface.Wrappers.LinearRing{false, false, Vector{Tuple{Int64, Int64}}, Nothing, Nothing}}, Nothing, Nothing}(GeoInterface.Wrappers.LinearRing{false, false, Vector{Tuple{Int64, Int64}}, Nothing, Nothing}[GeoInterface.Wrappers.LinearRing{false, false, Vector{Tuple{Int64, Int64}}, Nothing, Nothing}([(0, 0), (1, 0), (1, 1), (0, 1)], nothing, nothing)], nothing, nothing)
even though it will look correct when visualized, and indeed appears correct.
import GeometryOps as GO
GO.fix(polygon, corrections = [GO.ClosedRing()])
GeoInterface.Wrappers.Polygon{false, false, Vector{GeoInterface.Wrappers.LinearRing{false, false, Vector{Tuple{Float64, Float64}}, Nothing, Nothing}}, Nothing, Nothing}(GeoInterface.Wrappers.LinearRing{false, false, Vector{Tuple{Float64, Float64}}, Nothing, Nothing}[GeoInterface.Wrappers.LinearRing{false, false, Vector{Tuple{Float64, Float64}}, Nothing, Nothing}([(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.0, 0.0)], nothing, nothing)], nothing, nothing)
You can see that the last point of the ring here is equal to the first point. For a polygon with
Implementation
"""
ClosedRing() <: GeometryCorrection
This correction ensures that a polygon's exterior and interior rings are closed.
It can be called on any geometry correction as usual.
See also `GeometryCorrection`.
"""
struct ClosedRing <: GeometryCorrection end
application_level(::ClosedRing) = GI.PolygonTrait
function (::ClosedRing)(::GI.PolygonTrait, polygon)
exterior = _close_linear_ring(GI.getexterior(polygon))
holes = map(GI.gethole(polygon)) do hole
_close_linear_ring(hole) # TODO: make this more efficient, or use tuples!
end
return GI.Wrappers.Polygon([exterior, holes...])
end
function _close_linear_ring(ring)
if GI.getpoint(ring, 1) == GI.getpoint(ring, GI.npoint(ring))
the ring is closed, all hail the ring
return ring
else
Assemble the ring as a vector
tups = tuples.(GI.getpoint(ring))
Close the ring
push!(tups, tups[1])
Return an actual ring
return GI.LinearRing(tups)
end
end
This page was generated using Literate.jl.