@@ -101,59 +101,113 @@ function Base.iterate(tree::RTree, state::RTreeIteratorState)
101101 return get (new_state), new_state
102102end
103103
104- #=
105- TODO
106-
107- struct RTreeRegionQueryIterator{T,N,K,TT,R} <: SpatialQuery{T,N,K}
104+ # iterates R-tree data elements matching `Q` query w.r.t `region`
105+ struct RTreeRegionQueryIterator{T,N,V,Q,TT,R} <: SpatialQueryIterator{T,N,V,Q}
108106 tree:: TT
109107 region:: R
110108
111109 function RTreeRegionQueryIterator {T,N} (kind:: QueryKind , tree:: TT , region:: R ) where
112- {T, N, TT <: RTree{T,N}, R <: Region{T,N}}
113- new{T,N,kind,TT,R}(tree, region)
110+ {T, N, V, TT <: RTree{T,N,V } , R <: Region{T,N} }
111+ new {T,N,V, kind,TT,R} (tree, region)
114112 end
115113end
116114
117- contained_in(tree::RTree{T,N}, region::Region{T,N}) where {T,N} =
118- RTreeRegionQueryIterator{T,N}(QueryContainedIn, tree, region)
119-
120- intersects_with(tree::RTree{T,N}, region::Region{T,N}) where {T,N} =
121- RTreeRegionQueryIterator{T,N}(QueryIntersectsWith, tree, region)
115+ function Base. iterate (iter:: RTreeRegionQueryIterator )
116+ # no data or doesn't intersect at all
117+ if (isempty (iter. tree) || ! should_visit (iter. tree. root, iter))
118+ # @debug "iterate(): empty iter=$iter root_visit=$(should_visit(iter.tree.root, iter))"
119+ return nothing
120+ end
121+ return _iterate (iter, iter. tree. root, fill (1 , height (iter. tree)))
122+ end
122123
123- querytype(iter::RTreeRegionQueryIterator{<:Any,<:Any,K}) where K = K
124+ function Base. iterate (iter:: RTreeRegionQueryIterator ,
125+ state:: RTreeIteratorState )
126+ @inbounds ix = state. indices[1 ] = _nextchild (state. leaf, state. indices[1 ] + 1 , iter)
127+ if ix <= length (state. leaf) # fast branch: next data element in the same leaf
128+ return get (state), state
129+ else
130+ return _iterate (iter, state. leaf, state. indices)
131+ end
132+ end
124133
125- isok(iter::TreeRegionQueryIterator{T,N}, node::Any) where {T,N} =
126- intersects(iter.region, mbr(node) )
134+ """
135+ contained_in(index::SpatialIndex, region::Region )
127136
128- isok(iter::RTreeRegionQueryIterator{<:Any,<:Any,QueryContainedIn}, el::Any) =
129- contains(iter.region, mbr(node))
137+ Get iterator for `index` elements contained in `region`.
138+ """
139+ contained_in (tree:: RTree{T,N} , region:: Region{T,N} ) where {T,N} =
140+ RTreeRegionQueryIterator {T,N} (QueryContainedIn, tree, region)
130141
131- struct RTreeRegionQueryIteratorState{T,N,Y}
132- subtree::Vector{Node{T,N}}
133- end
142+ """
143+ intersects_with(index::SpatialIndex, region::Region)
134144
135- function next(iter::RTreeRegionQueryIterator{T,N},
136- state::RTreeRegionQueryIteratorState{T, N})
137- isempty(state.subtree) && return nothing
138- end
145+ Get iterator for `index` elements intersecting with `region`.
146+ """
147+ intersects_with (tree :: RTree{T,N} , region :: Region{T,N} ) where {T,N} =
148+ RTreeRegionQueryIterator {T,N} (QueryIntersectsWith, tree, region)
139149
140- function Base.iterate(iter::RTreeRegionQueryIterator)
141- # no root or doesn't intersect at all
142- iter.tree.root !== nothing || !isok(iter, iter.tree.root) || return nothing
143- subtree = push!(Vector{Node{T,N}}(), tree.root) # start with the root
144- return iterate(iter, RTreeRegionQueryIteratorState(subtree))
150+ # whether the R-tree node/data element should be visited (i.e. its children examined)
151+ # by the region iterator
152+ should_visit (node:: Node , iter:: RTreeRegionQueryIterator ) =
153+ intersects (iter. region, mbr (node)) # FIXME update for NotContainedIn etc
154+
155+ should_visit (el:: Any , iter:: RTreeRegionQueryIterator ) =
156+ ((querykind (iter) == QueryContainedIn) && contains (iter. region, mbr (el))) ||
157+ ((querykind (iter) == QueryIntersectsWith) && intersects (iter. region, mbr (el)))
158+ # FIXME update for NotContainedIn etc
159+
160+ # get the index of the first child of `node` starting from `pos` (including)
161+ # that satifies `iter` query (or length(node) + 1 if not found)
162+ @inline function _nextchild (node:: Node , pos:: Integer , iter:: RTreeRegionQueryIterator )
163+ if level (node) == 0 && length (iter. tree) > 100 && pos <= length (node)
164+ # @debug "_nextchild(): lev=$(level(node)) len=$(length(node)) pos=$pos should_visit=$(should_visit(@inbounds(node[pos]), iter)) rect=$(mbr(node[pos]))"
165+ end
166+ while pos <= length (node) && ! should_visit (@inbounds (node[pos]), iter)
167+ pos += 1
168+ if level (node) == 0 && length (iter. tree) > 100 && pos <= length (node)
169+ # @debug "_nextchild(): lev=$(level(node)) len=$(length(node)) pos=$pos should_visit=$(should_visit(@inbounds(node[pos]), iter)) rect=$(mbr(node[pos]))"
170+ end
171+ end
172+ return pos
145173end
146174
147- function Base.iterate(iter::RTreeRegionQueryIterator{T,N},
148- state::RTreeRegionQueryIteratorState{T,N})
149- isempty(state.subtree) && return nothing
150- node = pop!(state.subtree)
151-
152- node = next(iter, state)
153- if node === nothing
154- return nothing
155- else
156- return (node, state)
157- end
175+ # do depth-first search starting from the `node` subtree and return the
176+ # `RTreeIteratorState` for the first leaf that satisfies `iter` query or
177+ # `nothing` if no such leaf in the R-tree.
178+ # The method modifies `indicies` array and uses it for the returned iteration state
179+ function _iterate (iter:: RTreeRegionQueryIterator , nod:: Node , indices:: AbstractVector{Int} )
180+ node = nod
181+ # @debug"_iterate(): enter lev=$(level(node)) indices=$indices"
182+ @assert length (indices) == height (iter. tree)
183+ ix = @inbounds (indices[level (node) + 1 ])
184+ while true
185+ ix_new = _nextchild (node, ix, iter)
186+ # @debug "node=$(Int(Base.pointer_from_objref(node))) lev=$(level(node)) ix_new=$ix_new"
187+ if ix_new > length (node) # all node subtrees visited, go up one level
188+ while ix_new > length (node)
189+ if ! hasparent (node)
190+ # @debug "_iterate(): finished lev=$(level(node)) indices=$indices ix_new=$ix_new"
191+ return nothing # returned to root, iteration finished
192+ end
193+ # @debug "_iterate(): up lev=$(level(node)) indices=$indices ix_new=$ix_new"
194+ node = parent (node)
195+ @inbounds ix_new = indices[level (node) + 1 ] += 1 # next subtree
196+ end
197+ ix = ix_new
198+ # @debug "_iterate(): next subtree lev=$(level(node)) indices=$indices ix_new=$ix_new"
199+ else # subtree found
200+ ix_new > ix && @inbounds (indices[level (node) + 1 ] = ix_new)
201+ if node isa Branch
202+ # go down into the first child
203+ indices[level (node)] = ix = 1
204+ node = node[ix_new]
205+ # @debug "_iterate(): down lev=$(level(node)) indices=$indices"
206+ else # Leaf
207+ # @debug "_iterate(): return lev=$(level(node)) indices=$indices"
208+ state = RTreeIteratorState (node, indices)
209+ return get (state), state
210+ end
211+ end
212+ end
158213end
159- =#
0 commit comments