Skip to content

Commit 2bd4a45

Browse files
committed
Implement experimental edge iterators
like `eachedge`, `lazy_edge_extents`, `lazy_edgelist`, `to_edgelist`, etc. We may not want to do this - not sure here. Some options may also be suboptimal. And I encode f64 here in some places where I probably shouldn't...
1 parent 5e70c05 commit 2bd4a45

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

src/utils.jl renamed to src/utils/utils.jl

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,90 @@ function _point_in_extent(p, extent::Extents.Extent)
126126
(x1, x2), (y1, y2) = extent.X, extent.Y
127127
return x1 GI.x(p) x2 && y1 GI.y(p) y2
128128
end
129+
130+
#=
131+
# `eachedge`, `to_edgelist`
132+
133+
These functions are used to decompose geometries into lists of edges.
134+
Currently they only work on linear rings.
135+
=#
136+
137+
"""
138+
eachedge(geom, [::Type{T}])
139+
140+
Decompose a geometry into a list of edges.
141+
Currently only works for LineString and LinearRing.
142+
143+
Returns some iterator, which yields tuples of points. Each tuple is an edge.
144+
145+
It goes `(p1, p2), (p2, p3), (p3, p4), ...` etc.
146+
"""
147+
eachedge(geom) = eachedge(GI.trait(geom), geom, Float64)
148+
149+
function eachedge(geom, ::Type{T}) where T
150+
eachedge(GI.trait(geom), geom, T)
151+
end
152+
153+
# implementation for LineString and LinearRing
154+
function eachedge(trait::GI.AbstractCurveTrait, geom, ::Type{T}) where T
155+
return (_tuple_point.((GI.getpoint(geom, i), GI.getpoint(geom, i+1)), T) for i in 1:GI.npoint(geom)-1)
156+
end
157+
158+
# implementation for Polygon, MultiPolygon, MultiLineString, GeometryCollection
159+
function eachedge(trait::GI.AbstractGeometryTrait, geom, ::Type{T}) where T
160+
return Iterators.flatten((eachedge(r, T) for r in flatten(GI.AbstractCurveTrait, geom)))
161+
end
162+
163+
function eachedge(trait::GI.PointTrait, geom, ::Type{T}) where T
164+
return ArgumentError("Can't get edges from points, $geom was a PointTrait.")
165+
end
166+
167+
function eachedge(trait::GI.MultiPointTrait, geom, ::Type{T}) where T
168+
return ArgumentError("Can't get edges from MultiPoint, $geom was a MultiPointTrait.")
169+
end
170+
171+
"""
172+
to_edgelist(geom, [::Type{T}])
173+
174+
Convert a geometry into a vector of `GI.Line` objects with attached extents.
175+
"""
176+
to_edgelist(geom, ::Type{T}) where T =
177+
[_lineedge(ps, T) for ps in eachedge(geom, T)]
178+
function to_edgelist(ext::E, geom, ::Type{T}) where {E<:Extents.Extent,T}
179+
edges_in = eachedge(geom, T)
180+
l1 = _lineedge(first(edges_in), T)
181+
edges_out = typeof(l1)[]
182+
indices = Int[]
183+
for (i, ps) in enumerate(edges_in)
184+
l = _lineedge(ps, T)
185+
if Extents.intersects(ext, GI.extent(l))
186+
push!(edges_out, l)
187+
push!(indices, i)
188+
end
189+
end
190+
return edges_out, indices
191+
end
192+
193+
function _lineedge(ps::Tuple, ::Type{T}) where T
194+
l = GI.Line(SVector{2,NTuple{2, T}}(ps)) # TODO: make this flexible in dimension
195+
e = GI.extent(l)
196+
return GI.Line(l.geom; extent=e)
197+
end
198+
199+
function lazy_edgelist(geom, ::Type{T}) where T
200+
(_lineedge(ps, T) for ps in eachedge(geom, T))
201+
end
202+
203+
function edge_extents(geom)
204+
return [begin
205+
Extents.Extent(X=extrema(GI.x, edge), Y=extrema(GI.y, edge))
206+
end
207+
for edge in eachedge(geom, Float64)]
208+
end
209+
210+
function lazy_edge_extents(geom)
211+
return (begin
212+
Extents.Extent(X=extrema(GI.x, edge), Y=extrema(GI.y, edge))
213+
end
214+
for edge in eachedge(geom, Float64))
215+
end

0 commit comments

Comments
 (0)