@@ -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
128128end
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